Jump to content

Recommended Posts

Hi there processwire people,

this may sound obvious to most of you but not for me : )

I'm dealing with a booking form for a trip site.

I want the user to choose destination first (a select: let's say Venice, Rome and Hamburg);

Based on her choice, there will be days available (23 of august, 27 of september)

Based on the day, another select will show available times (e.g. 9.30, 15.30 and so on)

What should I do? Custom php or Form Builder? (I would prefer the latter...), and most of all: how to build a system like that?

Thanks!

Link to comment
Share on other sites

FormBuilder does not offer this out of the box as every field is self contained without any connection between them (besides inputfield dependencies). But you could still use FormBuilder to build the skeleton form. 

To build such a thing you've two options. Either load all available options and filter them on the client side by javascript or load only the options for the first select and use ajax to dynamically fetch and fill the other inputs based on previous selections. 

  • Like 3
Link to comment
Share on other sites

In my experience booking systems can get pretty complicated quickly. Even the smaller ones can potentially have a lot of interaction with the user which you have to account for. I would first map out the user interaction before deciding which way to approach the functionality. ProcessWire is built to handle this stuff, but there are several ways to build it depending on your exact needs. FormBuilder can be one if you just need a form which needs to be sent by email. If there is backend processing like checking if the trip is available in another system or if you want to prevent duplicate entries you would definately need do some custom PHP (even if you use FormBuilder).

  • Like 3
Link to comment
Share on other sites

I am currently looking into dependent select fields or cascading select fields (as they are sometimes called), too. So I have a quite similar scenario as yours. I already have setup some working code that I want to share here.

For a better understanding about my scenario:

1. parent countries with list of all countries
2. parent destinations, each destination gets assigned one country through "countries" pages asm select field.
3. parent tours, each tour gets assigned 1 or more countries through "countries" field and 1 or more destinations from "destinations" pages asm select field

In tours form, when countries are selected I want to filter the destinations field to only show destinations of the previously chosen countries.

For my solution I am using this jQuery plugin. So you need to call this in your template.

My code is still a work in progress and written around my requirements but should be fairly easy to transfer to other contexts.

Template code

<?php 
// do not load _main.php for ajax requests
if($config->ajax) $useMain = false; 

// provide dropdown data for the ajax request
if ($input->post->depdrop_parents) {
	
	$ids = $input->post->depdrop_parents;
	$params = $input->post->depdrop_params;
	$options = [];
	$option = [];

	if (count($ids) == 1) { // only 1 id
		$pages = $pages->find("template=$params[0], countries=$ids[0]");
	} // todo else { handle multiple ids}

	foreach ($pages as $page) {
		$option["id"] = $page->id;
		$option["name"] = $page->title;
		$options[] = $option;
	}

	echo json_encode(['output'=>$options, 'selected'=>'']);
}

// render the form
if (!$config->ajax) {
	$content = "";

	$destinations = $pages->find("template=destination,sort=countries.title");
	$options = [];
	$option = [];

	// build options array for first select field: this is very specific to my scenario
	foreach ($destinations as $destination) {
		if (seekKey($options, $destination->countries->first()->id) == $destination->countries->first()->id) continue;
		$option["value"] = $destination->countries->first()->id;
		$option["name"] = $destination->countries->first()->title;
		$options[] = $option;
	}

	$content = "<form>
	<select id='parent' name='countries'>";
	foreach ($options as $option) {
		$value = $option["value"];
		$name = $option["name"];
		$content .= "<option value='$value'>$name</option>";
	}
	$content .= "</select>";

	$content .= "<select id='child-1' name='destination'>
	</select>";

	// need hidden input with value "destination" to populate params for the JS plugin 
	// with the value that will be used as template value above in line 14
	$content .= "<input type='hidden' id='dest' value='destination'>

        //todo submit button and logic
	</form>";

}

In my functions.inc

// Find the value in a multidimensional array
function seekKey($haystack, $needle){
  $output = "";
  foreach($haystack as $key => $value){
    if($value == $needle){
      $output = $value;
    }elseif(is_array($value)){
      $output = seekKey($value, $needle);
    }
  }
  return $output;
}

Javascript

$(document).ready(function () {

    $("#child-1").depdrop({
        url: './',
        depends: ['parent'],
        params: ['dest'],    
        initialize: true
    });

});

Hope this helps.

  • Like 5
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

×
×
  • Create New...