cleanboy

Creating a payment form with Stripe

Recommended Posts

Hey all,

Mods; please feel free to move this if it is in the incorrect place although I thought this was the best place for it.

Kinda new to processwire but getting the hang of it....I am trying to build a payment form with the Stripe platform but failing miserably....I really hope someone can help!

So I am building my form with the PW API and also following through this documentation here: https://stripe.com/docs/elements and here: https://stripe.com/docs/charges

My form is pretty basic just for testing purposes right now:

<form id="payment-form" class="pusher" name="payment-form" method="post" action="./#booking-form">
			<?php
			$tokenName = $this->session->CSRF->getTokenName();
			$tokenValue = $this->session->CSRF->getTokenValue();
			echo '<input type="hidden" id="_post_token" name="' . $tokenName . '" value="' . $tokenValue . '"/>';

			$out = "";

			$out .= '<div id="card-number"></div>
			<div id="card-errors"></div>';

			// create a new form field (also field wrapper)
			$form = $modules->get("InputfieldForm");
			$form->action = "./";
			$form->method = "post";
			$form->attr("id+name",'payment-form');

			// First Name
			$field = $modules->get("InputfieldText");
			$field->skipLabel = true;
			$field->attr('id+name','name');
			$field->attr('placeholder','Full Name');
			$field->required = 1;
			$form->append($field); // append the field to the form

			// create email field
			$field = $modules->get("InputfieldEmail");
			$field->attr('id+name','email');
			$field->attr('placeholder','Email');
			$field->required = 1;
			$form->append($field); // append the field

			// oh a submit button!
			$submit = $modules->get("InputfieldSubmit");
			$submit->attr("value","SUBMIT");
			$submit->attr("id+name","submit");
			$submit->attr("class","cta white");
			$form->append($submit);

			if($input->post->submit) {

				// user submitted the form, process it and check for errors
				$form->processInput($input->post);

				if($form->getErrors()) {
					// the form is processed and populated
					// but contains errors
					$out .= $form->render();
				} else {
					foreach($input->post as $key => $value)
    					echo htmlentities("$key = $value") . "<br />";
				}
			} else {
				foreach($form->children as $input){
					$out .= "<div class='col-sm-6'>{$input->render()}</div>";
				}
			}
			echo $out;
			?>

		</form>

That alone works fine and returns all of the fields values after I click submit which is great...now we add the javascript:

//Stripe
	var stripe = Stripe('pk_test_*****************');
	var elements = stripe.elements();

	// Custom styling can be passed to options when creating an Element.
	var style = {
	  base: {
	    // Add your base input styles here. For example:
	    fontSize: '16px',
	    lineHeight: '24px'
	  }
	};

	// Create an instance of the card Element
	var card = elements.create('card', {style: style});

	// Add an instance of the card Element into the `card-element` <div>
	card.mount('#card-number');

	card.addEventListener('change', function(event) {
	  	var displayError = document.getElementById('card-errors');
	  	if (event.error) {
	    	displayError.textContent = event.error.message;
	  	} else {
	    	displayError.textContent = '';
	  	}
	});

	// Create a token or display an error when the form is submitted.
	var form = document.getElementById('payment-form');
	form.addEventListener('submit', function(event) {
	  	event.preventDefault();

	  	stripe.createToken(card).then(function(result) {
	    	if (result.error) {
		      	// Inform the user if there was an error
		      	var errorElement = document.getElementById('card-errors');
		      	errorElement.textContent = result.error.message;
	    	} else {
	      		// Send the token to your server
	      		stripeTokenHandler(result.token);
	    	}
	  	});
	});

	function stripeTokenHandler(token) {
		// Insert the token ID into the form so it gets submitted to the server
		var form = document.getElementById('payment-form');
		var hiddenInput = document.createElement('input');
		hiddenInput.setAttribute('type', 'hidden');
		hiddenInput.setAttribute('name', 'stripeToken');
		hiddenInput.setAttribute('value', token.id);
		form.appendChild(hiddenInput);

		// Submit the form
		form.submit();
	}

This gives an error in the console: Uncaught (in promise) TypeError: form.submit is not a function. 

This is because our submit input has the name "submit". Ok thats cool...I can change that but once I do the page essentially refreshes and the form just shows again and it doesnt give me the values it did before....I guess it isnt posting? either way after I submit the form after changing the name of the submit button the form just loads again and anything inside: if($input->post->submit) doesnt seem to execute...so what gives?

If anybody here has done this before with PW 3+ I would really love an example of how to use this to the point of sending information to Stripe.

I have installed Stripe with composer and it would appear that I can refer to it in Processwire just fine...my problem is just getting to the point where I need to refer to it which is after the submit.

I have seen the PaymentStripe module but tbh the documentation on that is somewhat lacking and im not even sure it works with the latest version of stripe? Im also not sure how to integrate that into a form either unless you use something along the lines of the example code provided after the form has been submitted but I cant even seem to submit the form to even try that and im not really sure why.

Here is the PaymentStripe module page for those wondering: https://modules.processwire.com/modules/payment-stripe/

Any help would be greatly appreciated!

Cleanboy

Share this post


Link to post
Share on other sites
45 minutes ago, cleanboy said:

This is because our submit input has the name "submit". Ok thats cool...I can change that but once I do the page essentially refreshes and the form just shows again and it doesnt give me the values it did before....I guess it isnt posting?

Change this

// oh a submit button!
$submit = $modules->get("InputfieldSubmit");
$submit->attr("value","SUBMIT");
$submit->attr("id+name","submit");
$submit->attr("class","cta white");
$form->append($submit);

if($input->post->submit) {

into

// oh a submit button!
$submit = $modules->get("InputfieldSubmit");
$submit->attr("value","1"); // any nonempty value would work!
$submit->attr("id+name","submitForm"); // change `name` attribute to something else to prevent name clash with form.submit
$submit->attr("class","cta white");
$form->append($submit);

if($input->post->submitForm) {

 

Share this post


Link to post
Share on other sites

Hey, thanks for the reply.

As I mentioned before, although maybe not too clearly, is that I have tried changing the button id+name and the form does submit but processwire doesnt process it. The page essentially refreshes and i just see the form fields again instead of outputting the result of 

if($input->post->submit) 

which should be 

foreach($input->post as $key => $value)
	echo htmlentities("$key = $value") . "<br />";

That if statement only seems to work as true when I name the button "submit" which i cant do because it overrides the javascript.

Share this post


Link to post
Share on other sites
17 minutes ago, cleanboy said:

That if statement only seems to work as true when I name the button "submit" which i cant do because it overrides the javascript.

if($input->post->$fieldName) works when there's a field named $fieldName inside the form and its `value` attribute evaluates to a truthy value. So when you change id+name of the`submit` button to `submitForm`, for instance, if ($input->post->submitForm) will work too.

Share this post


Link to post
Share on other sites

OOOOOohhhhhh! I did not notice the change of 

if($input->post->submitForm)

You suggested...

although I tried that and it didnt work either :(

Trying to limit the code as much as possible...this is what I have now:

<form id="payment-form" class="pusher" name="payment-form" method="post" action="./">
			<?php
			$tokenName = $this->session->CSRF->getTokenName();
			$tokenValue = $this->session->CSRF->getTokenValue();
			echo '<input type="hidden" id="_post_token" name="' . $tokenName . '" value="' . $tokenValue . '"/>';

			$out = "";

			$out .= '<div id="card-number"></div>
			<div id="card-errors"></div>';

			// create a new form field (also field wrapper)
			$form = $modules->get("InputfieldForm");
			$form->action = "./";
			$form->method = "post";
			$form->attr("id+name",'payment-form');

			// First Name
			$field = $modules->get("InputfieldText");
			$field->skipLabel = true;
			$field->attr('id+name','name');
			$field->attr('placeholder','Full Name');
			$field->required = 1;
			$form->append($field); // append the field to the form

			// create email field
			$field = $modules->get("InputfieldEmail");
			$field->attr('id+name','email');
			$field->attr('placeholder','Email');
			$field->required = 1;
			$form->append($field); // append the field

			// oh a submit button!
			$submit = $modules->get("InputfieldSubmit");
			$submit->attr("value","Submit Form"); // any nonempty value would work!
			$submit->attr("id+name","submitForm");
			$submit->attr("class","cta white");
			$form->append($submit);

			if($input->post->submitForm) {

				// user submitted the form, process it and check for errors
				$form->processInput($input->post);
              
					foreach($input->post as $key => $value)
    					echo htmlentities("$key = $value") . "<br />";
              
			} else {
				// render out form without processing
				//$out .= $form->render();
				foreach($form->children as $input){
					$out .= "<div class='col-sm-12'>{$input->render()}</div>";
				}
			}
			echo $out;
			?>

		</form>

It still just basically refreshes...well I cant tell what its doing...I dont really know how to debug this more effectively and actually see what is happening.

Share this post


Link to post
Share on other sites

1. You have two forms nested inside each other.
2. Here's a revised and simplified version:

<?php namespace ProcessWire;

// create a new form field (also field wrapper)
/** @var $form InputfieldForm */
$form = $modules->InputfieldForm;
$form->action = "./";
$form->attr("id+name", 'payment-form');
$form->addClass('pusher');
// $form->method = "post"; // default value

// add a single field quickly
$form->add([
    'type'        => 'text', // type is Inputfield<Type> without `Inputfield`
    'id+name'     => 'name',
    'placeholder' => 'Full Name',
    'required'    => 1,
]);

// add multiple fields quickly
$form->importArray([
    [
        'type' => 'email',
        'id+name' => 'email',
        'placeholder' => 'Email',
        'required' => 1,
    ],
    [
        'type' => 'submit',
        'id+name' => 'submitForm',
        'class' => 'cta white',
        'value' => 'Submit Form', // apparently value becomes the button label
    ],
    [
        'type' => 'markup', // add custom markup
        'value' => '<div id="card-number"></div>
                    <div id="card-errors"></div>'
    ]
]);

// CSRF token field is added by default


// Process input
if ($input->post->submitForm) {
    $form->processInput($input->post);
    if (!count($form->getErrors())) {
        // process credit card
    } else {
        // form has errors, append errors to the form
        $errors = join('<br>', $form->getErrors());
        $form->add([
            'type' => 'markup',
            'value' => '<div id="form-errors">$errors</div>'
        ]);
        echo $form->render();
    }
} else {
    // not posted, show the form
    echo $form->render();
}

 

  • Like 1

Share this post


Link to post
Share on other sites

Hey,

I got rid of the whole form I had and just copied that exactly and it still just refreshes when I click submit. The only difference being I was already declaring namespace ProcessWire at the top of the page before anything else but I dont think that is the problem.

I tried creating a separate php file and placing it in a folder I created called /site/php/ but the code did not execute from there....not even an echo "test" works.

Thanks for the help by the way...I really appreciate it.

Share this post


Link to post
Share on other sites

Here's the simplified version of your JS.

One thing you should look out for is that inside your form submit handler, you were preventing default submit action, but then submitting again without removing the handler, which caused the same routine to run repeatedly (submit? can't -> validate -> submit -> can't ,,, repeat).

When the form validates and you're ready to submit, remove the handler (that prevents the default action), so that the form can submit properly.

// Stripe API
var stripe = Stripe('pk_test_*****************');
var elements = stripe.elements();
// DOM Elements
var form = document.getElementById('payment-form');
var displayError = document.getElementById('card-errors');

// Card style
var style = {
    base: {
        fontSize: '16px',
        lineHeight: '24px'
    }
};

// Create an instance of the card Element
// Add an instance of the card Element into the `card-element` <div>
var card = elements.create('card', {style: style});
card.mount('#card-number');

card.addEventListener('change', function (event) {
    if (event.error) showError(event.error.message);
    else showError(); // remove previous error
});

form.addEventListener('submit', handleSubmit);

function handleSubmit(event) {
    event.preventDefault();

    stripe.createToken(card).then(function (result) {
        if (result.error) {
            return showError(result.error.message);
        }

        // remove previous errors
        showError();

        // Send the token to your server
        injectToken(result.token.id);

        // prevent infinite loop
        form.removeEventListener('submit', handleSubmit);

        // send the form
        form.submit();
    });
}

function injectToken(tokenId) {
    // Insert the token ID into the form so it gets submitted to the server
    var tokenInput = document.createElement('input');
    tokenInput.type = 'hidden';
    tokenInput.name = 'stripeToken';
    tokenInput.value = tokenId;

    form.appendChild(tokenInput);
}

function showError(errorMessage) {
    // if error is not given, remove previous error
    errorMessage = errorMessage || '';
    displayError.textContent = errorMessage;
}

 

  • Like 1

Share this post


Link to post
Share on other sites

Ok, this was a very weird problem.

It turns out that when submitting a form with JS, value of the submit button isn't posted with the form, that's why if ($input->post->submitForm) wasn't working as it would normally. We've solved the problem by checking for another field, `stripeToken`, to ensure that the form has been posted properly before processing the credit card.

https://stackoverflow.com/questions/1709301/javascript-submit-does-not-include-submit-button-value

Another way to solve this problem would be listening to submit button click instead of form submit, then preventing default action, validating the form with Stripe, and actually triggering click on the button.

  • Like 1
  • Thanks 1

Share this post


Link to post
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


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By MatthewSchenker
      Greetings Everyone,
      *************************************************
      *************************************************
      EDIT NOTE: This post started as a work-in-progress discussion as I was working out the elements of a successful form. After contributions from participants in this discussion, the code below has been tested and works well.
      You can use the code as shown below in your ProcessWire templates!
      Feel free to follow up with additional quesations/comments!
      *************************************************
      *************************************************
      I have successfully built front-end forms with ProcessWire to add pages via the API. It works great -- until I had to include image uploads along with the "regular" form fields.  Then it temporarily got a bit complicated.
      In this discussion, I show how to handle front-end submissions in ProcessWire with the goal of allowing us to create pages from custom forms.  I then go a step further and show how to use the same form to upload files (images and other files).

      I'm hoping this discussion can illustrate the whole process. I know a lot of people are interested in using ProcessWire to do front-end submissions, and my goal for this discussion is to benefit others as well as myself!

      First, here's my original contact form (no file uploads):
      <form action="/customer-service/contact/contact-success/" method="post"> <p><label for="contactname">Name:</label></p> <p><input type="text" name="contactname"></p> <p><label for="email">E-Mail:</label></p> <p><input type="email" name="email"></p> <p><label for="comments">Comments:</label></p> <p><textarea name="comments" cols="25" rows="6"></textarea></p> <button type="submit">Submit</button></form> And here's the "contact-success" page that picks up the form entry to create ProcessWire pages:
      <?php // First, confirm that a submission has been made if ($input->post->contactname) { // Save in the ProcessWire page tree; map submission to the template fields $np = new Page(); // create new page object $np->template = $templates->get("contact_submission"); $np->parent = $pages->get("/customer-service/contact-us/contact-submission-listing/"); // Send all form submissions through ProcessWire sanitization $title = $sanitizer->text($input->post->contactname); $name = $sanitizer->text($input->post->contactname); $contactname = $sanitizer->text($input->post->contactname); $email = $sanitizer->email($input->post->email); $comments = $sanitizer->textarea($input->post->comments); // Match up the sanitized inputs we just got with the template fields $np->of(false); $np->title = $contactname; $np->name = $contactname; $np->contactname = $contactname; $np->email = $email; $np->comments = $comments; // Save/create the page $np->save(); } ?> This works great! After submitting the form, we go to the "Success" page, and new submissions show up in the ProcessWire page tree right away. Excellent!

      Now I need to add a photo field. I altered the above form so it looks like this:
      <form action="/customer-service/contact/contact-success/" method="post" enctype="multipart/form-data"> <p><label for="contactname">Name:</label></p> <p><input type="text" name="contactname"></p> <p><label for="email">E-Mail:</label></p> <p><input type="email" name="email"></p> <p><label for="comments">Comments:</label></p> <p><textarea name="comments" cols="25" rows="6"></textarea></p> <p>Click the "Select Files" button below to upload your photo.</p> <input type="file" name="contact_photo" /> <button type="submit">Submit</button> </form> And here's the updated "contact-success" page:
      <?php // First, confirm that a submission has been made if($input->post->contactname) { // Set a temporary upload location where the submitted files are stored during form processing $upload_path = $config->paths->assets . "files/contact_files/"; // New wire upload $contact_photo = new WireUpload('contact_photo'); // References the name of the field in the HTML form that uploads the photo $contact_photo->setMaxFiles(5); $contact_photo->setOverwrite(false); $contact_photo->setDestinationPath($upload_path); $contact_photo->setValidExtensions(array('jpg', 'jpeg', 'png', 'gif')); // execute upload and check for errors $files = $contact_photo->execute(); // Run a count($files) test to make sure there are actually files; if so, proceed; if not, generate getErrors() if(!count($files)) { $contact_photo->error("Sorry, but you need to add a photo!"); return false; } // Do an initial save in the ProcessWire page tree; set the necessary information (template, parent, title, and name) $np = new Page(); // create new page object $np->template = $templates->get("contact_submission"); // set the template that applies to pages created from form submissions $np->parent = $pages->get("/customer-service/contact-us/contact-submission-listing/"); // set the parent for the page being created here // Send all the form's $_POST submissions through ProcessWire's sanitization and/or map to a variable with the same name as the template fields we'll be populating $np->title = $sanitizer->text($input->post->contactname); $np->name = $np->title; $np->contactname = $sanitizer->text($input->post->contactname); $np->email = $sanitizer->email($input->post->email); $np->comments = $sanitizer->textarea($input->post->comments); $np->save(); // Run photo upload foreach($files as $filename) { $pathname = $upload_path . $filename; $np->contact_photo->add($pathname); $np->message("Added file: $filename"); unlink($pathname); } // Save page again $np->save(); ?> <p>Thank you for your contact information.</p> <?php return true; } else { ?> <p> Sorry, your photo upload was not successful...</P> <?php } ?>
      Replace the field references with your own field names, make sure to change the various paths to match yours, and change the various messages to be what you need for your project.
      Read the entire discussion to see how we worked through getting to the solution shown above.

      Thanks,
      Matthew
    • By bmacnaughton
      I had situations come up that just seemed like AJAX was the right way to handle interactions with the ProcessWire server - pages with an element like a button or link that should cause an action to occur but shouldn't require a form or actually following a link - it should just take the action and only update the toggle (a checkbox in this case) when the interaction is completed.

      Another use case is with a large page on which there are multiple possible interactions. When the page is heavy enough that redrawing results in a less than optimal user experience then it's nice to be able to submit a form without having to redraw the page in order to update the relevant parts.
      So with that preamble, here's what I put together. I was going to try to clean it up a bit but that has prevented me from posting this so I figured it's better to post it and clean it up if there is any interest. You'll see references to the namespace whale - the name of our project - that would ultimately be removed.
      There are two major components - the PHP side and the client-side.
      On the PHP side there are two functional areas:
      1. "wrapping" an entity to be inserted into the HTML on a page 
      Wrapping (the function 'makeContainer()' puts a predefined wrapper around one of three types of objects: FormBuilderForm, InputfieldForm, or Template).  The wrapper provides context and attaches classes that allows the client JavaScript code to find the wrapper and figure out what to do with it.
      // // define a function that makes a "form" of a single button. // function makeButton ($label) { // get the form $form = wire('modules')->get("InputfieldForm"); $form->attr('action', './'); $form->attr('method', 'post'); $submit = wire('modules')->get("InputfieldSubmit"); $submit->attr('id+name', 'submit'); $submit->attr('value', $label); $form->add($submit); return $form; } // wrapper function to set label on submit button function requestUserDeleteList() { return makeButton('Do it!'); } // // makeContainer wraps the rendered InputfieldForm in HTML so the client JavaScript can recognize it and handle // AJAX interactions with the server. // It returns the InputfieldForm object and the HTML to be inserted into the page. Note that makeContainer // is in a different namespace so it requires the function name must be qualified with the \ProcessWire prefix. // list ($form, $deleteUsersHTML) = ajax\Request::makeContainer('do-something', '\ProcessWire\requestUserDeleteList'); 2. helping with the processing of an AJAX request that is submitted to the page.
      Helping with the AJAX request - the code is invoked on page load and determines where there is a valid AJAX request from something it wrapped. It also allows messages to be returned, classes to be added or removed from specific elements, redirects to be executed, or even wholesale replacement of DOM elements (with plenty of caveats). It will even update a submit key so it is possible for the client to execute a single transaction multiple times.
      // get a new request object for the AJAX transaction $request = new ajax\Request(); // if it isn't formatted correctly handle the error if (!$request->isValidCall()) { return $request->echoError(); } // get the data and function-specific contents (Whale Ajax Context) $data = $request->data(); $wac = wireDecodeJSON($data['wac']); // if ($request->id('wants-newsletter')) { if (!ajax\Request::hasCorrectProperties($data, ['wac', 'value'])) { return $request->echoError(__('invalid call')); } // implement function here } else if ($request->id('another-function')) { // implement function here } // it didn't match any of the AJAX IDs implemented return $request->echoError('not implemented');  
      The client code requires jQuery and is packaged as three separate functions because both the form and template processing share a common core set of functions. My original intent was to only load the form or non-form code as needed but they're small enough that it really doesn't matter.
      See attachments for the Request class and the client code. There are many helper functions.
      Here is a kind of an unfocused extract that illustrates using the code with more context (from an internal sandbox page):
      <?php namespace ProcessWire; using whale\ajax; // include server-side code for making forms and processing them require_once './utility/ajaxform.inc'; // custom version of ProcessWire/wire/core/WireFileTools.php render() that returns the // template object, not the rendered HTML require_once './utility/get-file-template.inc'; // START AJAX submitted form processing - decodes the request and stores results in $aaform. $aaform = new ajax\Request(); // // this page handles multiple ajax calls so I check to see if it is valid once and then check IDs. // It's also possible to use $aaform->isValidCall('get-user-delete-list') to check specifically // for a specific AJAX ID. The ID is the name provided to Request::makeContainer() when the object // is wrapped. It's also possible to make calls to $aaform->id('get-user-delete-list') to check // for a specific ID. // // to create the forms/input elements that are submitted via AJAX start with: // Request::makeContainer('unique-name-on-page', object) // unique-name-on-page will become the ID of the element that wraps your object. // object - one of ProcessWire\InputfieldForm, \FormBuilderForm, ProcessWire\Template. // if ($aaform->isValidCall()) { if ($aaform->id() === 'get-user-delete-list') { $form = requestUserDeleteList(); // process using the form. the Request object will check to make sure it's the right type. if (!$aaform->process($form)) { return $aaform->echoError(); } // build new form with usernames for selections to delete. the function getUsersToDelete() // returns a user count and a function that will make the form that includes the users in // a list of checkboxes. list($usercount, $formmaker) = getUsersToDelete(); // this returns a replacement to part of the existing DOM. There are limitations but it // handles adding a form or replacing an existing form. if ($usercount === 0) { $replacement = '<div id="ajax-place">No users to delete</div>'; } else { // we pass the $formmaker function to makeContainer(). It returns the form and the // rendered wrapper and form. list($xform, $xhtml) = ajax\Request::makeContainer('do-delete', $formmaker); $replacement = '<div id="ajax-place">' . $xhtml . '</div>'; } // this makes sure the return is formatted so the client can handle it correctly. in // this case a replacement in the DOM is being returned. The first argument is the // selector, the second is the HTML to replace the selected element with. return $aaform->echoReplacement('#ajax-place', $replacement); } else if ($aaform->id() === 'do-delete') { list($usercount, $formmaker) = getUsersToDelete(); // process using the form returned by $formmaker. this will check to make sure it's // the right type of form. This abstracts FormBuilder forms and InputfieldForms. if (!$aaform->process($formmaker())) { return $aaform->echoError(); } // a bunch of logic where the checked users are deleted $deleted = []; $failed = []; $data = $aaform->data(); foreach($data as $name => $value) { if ($name === $value) { $user = wire('users')->get("name=$name"); $email = $user->email; // delete the user and try to get it again to see if the delete worked wire('users')->delete($user); $u = wire('users')->get("name=$name"); if (!count($u)) { $deleted[] = $email . " ($name)"; } else { $failed[] = $email . " ($name)"; } } } $deleted_users = $failed_deletions = ''; if ($deleted) { $deleted_users = 'deleted:<br/>' . join($deleted, '<br/>') . '<br/>'; } if ($failed) { $failed_deletions = 'failed to delete:<br/>' . join($failed, '<br/>') . '<br/>'; } $replacement = '<div id="ajax-place">' . $deleted_users . $failed_deletions . '</div>'; return $aaform->echoReplacement('#ajax-place', $replacement); } else if ($aaform->id() === 'contact') { // here a FormBuilderForm is being loaded if (!$aaform->process($forms->load('contact'))) { return $aaform->echoError(); } // this sends a notice back. the client will place it in a predefined notice area. // Request::makeContainer() will create an area for notices (or you can supply one). // It is also possible to return errors; notices and errors get different classes. $msg = ajax\Request::makeNotice('bruce says hi'); return $aaform->echoSuccess($msg); } else { // it was a valid form but it doesn't match any ID that this page knows about. return $aaform->echoError('what is this?'); } } // normal processing to render the initial page follows as it was not a valid AJAX post // that is handled by Request(). That's a lot of code, so I won't post anymore. If people have interest I'm happy to explain or provide other bits of code, like the extracted get-file-template.inc function.
      Wrapping a template is similar to wrapping a form except that only certain HTML elements are tracked and each are sent to the server when they are clicked on (technically it varies). It handles radio buttons, checkboxes, links, and buttons (radios and checkboxes on "change" and links and buttons on "click"). So when a checkbox is checked an AJAX call will be made so it can be acted upon by the server.
       
      @microcipcip, @ryan, @valan (sorry to any if this isn't interesting to you - I did a quick scan of what looked like semi-related AJAX posts).
       
       
      ajaxform.inc
      ajaxclient.js
    • By Oleg
      hello!
      I have a site on processwire version 2.3.
      Can I install Form builder, and will it work?
    • By NoremPload
      is there a simple way to render a form from the backend in frontend ( with other styles ) ? Or do i have to build everything on my own like in this post 
      ?
      Thanks for any help.
    • By modifiedcontent
      I need to figure out how to make a simple front end event registration/RSVP; enter full name + email address for the guest list (database), receive an email confirmation.
      Where to start with this? I know how a regular html form works. What does a basic Processwire form look like?