Ajax Driven Dropdown Lists for ProcessWire made easy

Frontend Example 1: Continents, Countries and Cities

This example is about using Dynamic Selects in the frontend.

The processes of setting up Dynamic Selects for backend or frontend use are pretty similar. We have previously looked at an example use of Dynamic Selects in the backend. In this tutorial of how to use the module in the frontend, we got a bit further and show you how to leverage the power of the include and exclude templates/pages/fields settings. We will be building a Dynamic Selects composed of a three columns to filter Continents, Countries and capital Cities data. Lets get started.

Site Structure

We will not go into detail on how to set up your templates for this example as we already did that in a previous tutorial. The structure of our site in this example is simple though. We have a parent page called Countries of the World. This parent page uses a template called world. The parent page has 6 children corresponding to continents of the world, i.e. Africa, Asia, Europe, North America, Oceania and South America. All 6 child pages use the template continent.

Each of the continent pages has children pages which are countries in those continents. For instance, amongst the children of Africa are Algeria, Botswana and Chad. For Oceania we have Fiji, Nauru and Tonga, etc., and so on for the other continents. Each country page uses a template named after its parent page. So, European countries use the template europe, North American, north-america, etc.

In turn, each country has its capitial City as its only child page. Some good resources for Country lists as well as their related data can be found here and here.

Create a Dynamic Selects in ProcessDynamicSelects

Once we got our site structure ready, it's time to create the Dynamic Selects. Launch ProcessDynamicSelects by clicking on the menu item Dynamic Selects in your ProcessWire Admin. Open up the Add Selects textarea and create one Dynamic Selects. I called mine Countries of the World. Click on button Publish to create the Dynamic Selects. You should see the newly created Dynamic Selects in the list of selects in the table below. Click on its title to edit it.

Take a look at the URL of that page. Take note of the ID of the Countries of the World Dynamic Selects page. It should be something like:

/your-processwire-admin/dynamic-selects/edit/?id=1234

The 1234 is the ID of this Dynamic Selects page. Jot it down since we will need it later.

First Dropdown

This dropdown will display the titles of our 6 continents. As you've previously learnt, the data for the first/initial column will be populated based on two other settings; the First Column Data Source and either the First Column Selector or First Column Custom PHP Code.

For the first column's data source specify Pages. For our second setting we will use the following Custom PHP Code.

return $pages->get('/countries-of-the-world/')->children;

There is nothing complicated in that code. All we are telling the module is to get the parent page Countries of the World then find its children, i.e. our 6 continents.

Scroll down to the Dynamic selects columns settings. In the first row on the table there, enter the details of our first dropdown. I used Continent in both the Name and Label inputs. The Process module will sanitize the name to continent on save. For Trigger, Relationship and Data Source we do not need to do anything. OK, let's move on to the other dropdowns. Do not save anything yet since we have not finished setting up and the module will return an error.

Second Dropdown

Click on the add column link to create a second row. A new row will be added to the column settings table. The Trigger input should be pre-populated for us with the first column's name, i.e. continent

We will use this dropdown to display a list of countries depending on the continent selected in the first column. For Name and Label we use Country. Again, the name will be sanitized to country when we save the Dynamic Selects.

Since the country pages are children of their respective continent parent pages, the relationship here is easy. The data in the second dropdown is related to its trigger column as a child page. Hence, for Relationship we select Child. For Data Source we select Title. We are done with this dropdown.

Third Dropdown

Click on add column link again to create a third row. The pre-populated Trigger input should read country. For Name and Label we use Capital. For Relationship we select Child again since capital Cities are children of their respective countries. You can go ahead and save the Dynamic Selects but do not exit it yet. We still have some settings to complete.

Edit Settings

Head over to the Settings Tab. There's a number of settings here. We have already seen what each do. In this example, we will only have a play with the cache, the users' access (to control who can view the selects in the frontend) and the include/exclude settings.

Who Can View?

For 'which users can view the select in the frontend' setting, we leave the default selected, i.e. Logged in users.

Cache Data

We want to cache the data for this Dynamic Selects for faster load times and less ajax requests. Some continents have lots of countries and we do not want to be fetching this afresh on every request.

Click on the checkbox Cache selects data. That will open up a input labelled Cache time just below it. Enter the number of seconds that you want this cache to live for before it is renewed. Although our list of countries will probably never change any time soon, as an example, we set the cache to expire after two hours. Hence, we enter 7200 for this setting. Click on the button Save.

When this Dynamic Selects will be viewed in the frontend, that action will cause the module to create a cache both server-side (a WireCache) and client-side of any successfully returned data. In addition, when a user requests data they have previously request using the same browser, the module will fetch the data from the local cache rather than from the server. When the page is refreshed, the module will fetch data from remote cache, ready to populate the Dynamic Selects. Please note that the cache time has no direct influence on the life of the local cache.

Include/Exclude Templates/Pages/Fields

For this setting, head back to the Build Tab. Expand the Include/Exclude: Templates, Pages, Fields fieldset. If you haven't already done so, please thoroughly read the Usage Notes. We are not going to change anything here yet but will come back to this once we've displayed the Dynamic Selects in the frontend. This way, we can see the different changes as we include/exclude templates/pages into/from the results. We do this next.

Display in Frontend

In the previous topic we learnt how to output frontend Dynamic Selects using MarkupDynamicSelets API. We saw an example template file and familiarized ourselves with the various methods in MarkupDynamicSelects that we need to ouput Dynamic Selects in the frontend. Hence, we need not go into details in this tutorial. Go head and edit the template file where you want our newly created frontend Dynamic Selects to be displayed. Use the ID of the page of the Dynamic Selects that we jotted down earlier in this tutorial.

Visit a page that uses the above template file. If you set up everything correctly you should see your Dynamic Selects displayed on that page. Remember we are in the frontend. Remember also that selections made in this Dynamic Selects are temporary since frontend Dynamic Selects are not saved. Make a selection in the first select. For instance, select the Continent South America. The second select should be pre-populated with the countries in that continent. Select one of the countries, e.g. Peru. Its capital (Lima) will be selectable in the third select. Simple, right? Right!

Cached Data

Remember that in our settings we chose to cache the data returned in this Dynamic Selects. If you check in your browser developer tools console, you should see the module makes an ajax request for data only on the first request for that particular selection. For instance, when we first selected South America. an ajax request was sent to the server. Subsequently, selecting South America again will draw from the local cache; there will be no ajax-request. Conversely, selecting a different continent, say Oceania, will trigger an ajax request. Subsequent requests for this same continent will be made to the local cache.

If the page is reloaded and there have been no changes server-side (in relation to the first select) and the cache has not expired, our local cache will be rebuilt with data from the remote cache. When the cache expires, an new one will be created and progressively built as more data is requested by your web visitors.

Filtering In/Out Data/Results

Now for some more fun. Let's say that we want to only show some countries and not others. There are several ways we can accompish this. We can:

  1. Unpublish the pages.
  2. Make the pages hidden.
  3. Activate access-control in their templates.
  4. Use Dynamic Selects inclusions/exclusions settings.

The first 3 options in our list could be a bit tedious to set up. Instead, we use the 4th option; inclusions/exclusions settings. It is important to note that there is no need to use all 4 options at the same time for the same page(s) if all we wanted was to exclude some results. For instance, if a page with ID 1234 is unpublished, it will automatically be excluded from results.

Included Templates and Included Pages

Imagine that we want to ONLY include Asian and Oceanian countries in the results returned in the second dropdown, i.e. the Country column. However, we want to make an exception for a few European countries to be included also in the results. This is easy to achieve.

First, make a note of the IDs of the templates 'asia' and 'oceania'. In this example these are 95 and 98 respectively. We also want to include the European countries Germany, Greece, Hungary, Iceland, Italy, Monaco and Slovakia. We also note their IDs. In our case these are 1630, 1631, 1632, 1633, 16341656 and 1676 respectively. 

Secondly, in the textarea labelled Included Templates we enter the following:

country,95,98

Thirdly, in the textarea labelled Included Pages, we enter the following:

country,1630,1631,1632,1633,1634,1656,1676

In both inclusions above, country refers to the Name of the column where we want the inclusions to apply. If we needed an include for a different column, we would just enter those in a new line. This has been covered in a previous topic.

Save our Countries of the World Dynamic Selects. Visit the frontend of the page where this Dynamic Selects is rendered and reload it. Select a continent. You will see that for the continents Asia and Oceania all their respective countries are loaded in the second dropdown. For Europe, only the 7 countries we included in Included Pages above are returned. For all other continents no results are returned; awesome! It works.

Let's have a look at our Included Pages again. What do you notice? That's right, the first 5 pages' IDs are sequential. We can make our inclusions easier here. Remember we can enter inclusions/exclusions IDs as comma-separated values or a range of values or both. In our case, we can do the latter. Let's change our Included Pages setting as indicated below and save the Dynamic Selects.

country,1630-1634,1656,1676

That's much easier! Visit the frontend again. The results should be the same as when we first applied these inclusion settings. How about excluding some pages instead. Let's try that next.

Included Templates and Excluded Pages

There will be times when we want to ONLY show pages that use a certain template(s) but within those, exclude some. In this scenario, we want to include Asian and Oceanian countries. Within Asian countries, we want to, however, exclude Philippines, Qatar, Saudi Arabia, Singapore, South Korea and Sri Lanka. Their respective page IDs are 1573, 1574, 1575, 1576, 1577 and 1578. For Oceanian countries, we wish to exclude the countries Australia, Federated States of Micronesia, Fiji and Kiribati. Their IDs are 1740, 1741, 1742 and 1743 respectively.

Our work is easy here since the groups of IDs happen to be sequential. Let's implement the inclusions and exclusions. We want to only include Asian and Oceanian countries so in the textarea Included Templates we enter the following:

country,95,98

Before we exclude some pages, we make sure that the Included Pages input (textarea) is empty. This is because includes have precedence of excludes. Next, in the Excluded Pages input we enter the following:

country,1740-1743,1573-1578

As you can see, the order of the two page ID ranges does not matter; we started with the higher numbers, then entered the lower ones. The same is true even when we use comma-separated values (or both of these).

Save the Dynamic Selects and check it out in the frontend. Notice the changes. In the second dropdown, no other countries are returned except Asian and Oceanian minus the ones we excluded. Neat! Next, we exclude by templates but include by pages.

Excluded Templates and Included Pages

Let's change some things around. Now we want to exclude all Asian and Oceanian countries, returning only countries from the other 4 continents. However, we make a few exceptions for the countries that would otherwise would have been excluded. We want to retain the Asian countries China, Japan and Kyrgyzstan, whose respective page IDs are 1571, 1541 and 1549. We also want to retain Palau (ID 1754) and Papua New Guinea (ID 1756), two countries in Oceania.

You know the drill by now. Delete any entry in the Included Templates input. Then, in the Excluded Templates input, enter the following:

country,95,98

Remove any entries in the Excluded Pages input then in the Included Pages input, enter the following:

country,1571,1541,1549,1754,1756

Save the Dynamic Selects. Head over to the fronted where we have the Countries of the World Dynamic Selects rendered and reload the page. Try selecting different continents in the first dropdown and note the countries returned in the second dropdown each time. All continents now return their countries. There is one major difference though; in the case of Asia and Oceania, only the 5 countries we included aboveare returned; 3 (China, Japan and Kyrgyzstan) and 2 (PalauandPapua New Guinea), respectively for these continents. Brilliant!

Finally, how about we exclude by templates and also exclude by pages. This is useful when you wish to exclude pages by their templates but also exclude several pages that would otherwise have been included. Let's look at this next.

Excluded Templates and Excluded Pages

In this scenario, we want to exclude Asia and Oceania results. This means we want ONLY countries in Africa, Europe, North America and South America to be returned. However, amongst these, we also wish to exclude a number of countries. From Africa, these are: Djibouti (1428),  Egypt (1429), Equatorial Guinea (1430) and Gabon (1438); EuropeCzech Republic (1620), Finland (1625), France (1626), Germany (1627) and Greece (1628); North AmericaAntigua and Barbuda (1693), United States (1737) and Nicaragua (1725); and South AmericaUruguay (1789).

Armed with these info, we are ready to roll. If you still have what we entered last in Excluded Templates, you can skip that bit. If not, enter the following in that input area:

country,95,98

Clear out what we had in Included Pages. Instead, enter the following in Excluded Pages:

country,1428-1430,1438,1620,1625-1628,1693,1737,1725,1789

Save then view the Dynamic Selects in the frontend. All Asian and Oceanian countries are excluded from the results in the second dropdown. The other remaining continents each return all their countries except those we excluded. Excellent job!

This concludes examples on the combined usage of included/excluded templates/pages. The exclusive use of one or the other is pretty straightforward. Below are two scenarios.

Included Templates

In case we wanted to ONLY return countries from Asia and Oceania and no other, without exceptions, we would use ONLY this setting. First, clear the input Excluded Templates as well as both Included and Excluded Pages inputs. Then, in Included Templates, enter the following:

country,95,98

If you save then view the Dynamic Selects in the frontend, you will see only these 2 continents' countries returned in dropdown number 2.

If instead we wanted to exclude these templates we would of course exclusively use Excluded Templates instead. That would exclude all countries from these continents from the results in the second dropdown

Excluded Pages

We would use Excluded Pages if we wanted to show ALL countries in ALL continents except the excluded ones. Let's say we wanted to exclude Finland (1625), Germany (1627) and Uruguay (1798). We would enter the following in the input Excluded Pages. In this case, we would make sure the both the inputs for Included and Excluded Templates were empty as well as the input for Included Pages.

country,1625,1627,1798

Similarly, if instead we needed to ONLY include these pages and no other, we would instead utilise Included Pages.

That concludes this lesson. We have previously looked at how to use the Included/Excluded Fields setting and need not repeat that here. To sum up, we have seen how we can leverage the power of the settings Included and Excluded Templates and Pages, especially when used in combination. We were also reminded that unpublished, hidden or template access-controlled pages are never returned in Dynamic Selects results. Hence, in the case exclusions, such pages will already be excluded.