Jump to content
darrenc

Dynamic page field that depends on value of previous field entry?

Recommended Posts

Is it possible to make a page field, that outputs options based on what a user has selected in a previous page field?

Template data setup

  • house (template)
    • title (text)
    • body (textarea)
    • neighborhood (page field)
  • neighborhood (template)
    • title (text)

Obviously it's set up with lots of neighborhood pages, and if you create a house you get a dropdown of those neighborhoods which you can select. 

What I want to do

  • featured_neighborhood (template)
    • title (text)
    • body (textarea)
    • neighborhood (page field)
    • homes_in_neighborhood (page field)

The goal would be for the user to create a new featured neighborhood, choose the neighborhood reference, and then homes_in_neighborhood would be a selection dynamically created from whatever neighborhood that is.

Is this possible in PW? Thanks in advance!

Share this post


Link to post
Share on other sites

You can do this with the undocumented dependent selects feature, which AJAX loads the selectable pages in a Page Reference field based on the value of another Page Reference field in the same page being edited.

Your "homes_in_neighborhood" field would use this as the "Selector string" setting:

neighborhood=page.neighborhood, neighborhood!=''

You can limit by template, parent, etc too if you want.

Based on my previous experience:

  • Both Page Reference fields must use a Select, Select Multiple or AsmSelect inputfield.
  • Dependent selects do not work inside Repeater fields.
  • When changing the "source" Page Reference field you sometimes randomly get an option preselected in the "target" Page Reference field. Not a major problem but just something to keep an eye on to avoid accidentally saving an unintended value.

If these limitations are a problem and you don't mind having to save the page after changing the "neighborhood" field then you can use the "Custom PHP code" option for selectable pages instead.

  • Like 4
  • Thanks 1

Share this post


Link to post
Share on other sites
On 16.02.2017 at 10:38 PM, Robin S said:

Dependent selects do not work inside Repeater fields.

@Robin S Do you mean inside a repeater field or if items inside 'parent' Page reference field is repeater items? It seems like it doesn't work in both cases. 

Share this post


Link to post
Share on other sites
6 hours ago, Zeka said:

Do you mean inside a repeater field or if items inside 'parent' Page reference field is repeater items?

I mean inside a repeater field. Technically it will work there, but not in a useful way. The issue being that the names of inputfields inside a repeater item have a suffix according to the ID of the repeater page. So you would have to include the suffix in the selector for the dependent Page Reference field and therefore it would only ever work inside a single repeater item.

Should be no problem if the pages that make up the selectable options in a Page Reference field happen to be repeater pages. They are treated the same as any other page inside the field.

Share this post


Link to post
Share on other sites

It's a while since this thread has been updated, so I thought I'd check whether there's been any update on anyone finding a way to make dependent selects work dynamically inside repeaters.

I've got dependent selects inside repeaters working ok IF I save each time I make a selection, but that's a bit clunky for an end user. I realise there are issues with the way repeaters generate ids that might make ajax based updates impossible but it would be handy.

I originally rejected using pagetables as there are only every going to be a handful of repeater items for each page, and the modal edit method with pagetable fields, rather than inline editing, along with the need to publish each item is not as intuitive as repeaters. A repeater field would be my preference, although I guess I could go back to using pagetables/pagetable extended, but they're not as convenient for end users as a repeater, apart from the issue around dynamic selects.

Share this post


Link to post
Share on other sites
On 11/29/2019 at 8:43 PM, Kiwi Chris said:

It's a while since this thread has been updated, so I thought I'd check whether there's been any update on anyone finding a way to make dependent selects work dynamically inside repeaters.

I had a play around and this hook seems to do the job:

Edit: the hook doesn't work because the selected pages are lost on page save. Maybe related to the discussion in this issue.

$wire->addHookBefore('InputfieldPage::render', function(HookEvent $event) {
	/* @var InputfieldPage $inputfield */
	$inputfield = $event->object;
	$page = $inputfield->hasPage;
	$field = $inputfield->hasField;
	// Return early if inputfield is not in a Repeater page
	if(!$page instanceof RepeaterPage) return;
	$selector = $inputfield->findPagesSelector;
	// Return early if no selector or selector doesn't include a dependency
	if(!$selector || strpos($selector, '=page.') === false) return;
	// Get suffix added to inputfields in this Repeater page
	$suffix = str_replace($field->name, '', $inputfield->name);
	// Add the suffix to dependency inputfield names
	$selector = preg_replace('/(=page.[_a-zA-Z0-9]+)/', "$1{$suffix}", $selector);
	// Replace the original findPagesSelector
	$inputfield->findPagesSelector = $selector;
});

Demo...

Page tree:
2019-11-30_145134.png.b477bb8ecf501314504c6d922a69668a.png

Selector string for Subcategory field:
2019-11-30_145023.png.a1619dabcca96ee9d25d2978f35fd1f9.png

Page Edit:

dependent.gif.d90df113c431bacc4e8ec9429ffe629c.gif

 

Edited by Robin S
Hook doesn't work.
  • Like 5

Share this post


Link to post
Share on other sites

@Robin S That seems to partially work, but it seems to have issues if a custom selector returned by a hook in ready.php, rather than a selector configured in the field properties.

I'm not sure if there's a way around that?

Share this post


Link to post
Share on other sites
1 hour ago, Kiwi Chris said:

That seems to partially work, but it seems to have issues if a custom selector returned by a hook in ready.php, rather than a selector configured in the field properties.

I'm not sure if there's a way around that?

The dependent selects feature has only ever worked with the selector string option as far as I know.

Share this post


Link to post
Share on other sites

Hi,
thanks @Robin S for your hook example, but also (in my case) I had a problem to save values inside repeaters.
I use 3 fields per/row and out of repeaters everything works fine (PW 3.0.146.). The images below shows my page tree and two different situations (after save).
pw.png.994e1c97fc5f3d218cb56426420d5aea.pngok-1.thumb.png.4af6cc59b73d59b8dc03b2f5aca2567f.pngnok-1.thumb.png.0f3f2228c4548e7f0642c0532d1b9375.png

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Here is another hook example ("cascade" case like on images) but before test, please read setup notes:
1) For the first column field (continents / categories) set parent page inside field setup.
2) For subfields (country and city) set template (eg. "blank") inside field setup.
3) Write selector strings for subfields inside hook configuration (ready.php).

category-field.jpg.ef24ce764468ad66dd8b043175359c66.jpg
pw-ok-setup.png.4985c25a95461b356feb2fbfff6ee992.png

 

 

PHP (ready.php)

<?php namespace ProcessWire;

/**
 *  Configuration:
 *  Field names and selectors
 *
 *  For subfields and after save problem
 *  need to write string selectors here, and leave empty
 *  that part inside field setup.
 */

$config->names = array(
    'continent' => '',
    'country' => 'parent=page.continent',
    'city' => 'parent=page.country',
);

$wire->addHookAfter('InputfieldPage::getSelectablePages', function ($event) {

    $inputfield = $event->object;
    $field = $inputfield->hasField;
    $names = $this->config->names;

    if (isset($names["$field->name"])) {
        $selector = $names["$field->name"];
        if (trim($selector) !== "") {
            if (strpos($inputfield->name, '_repeater') !== false) {
                $id = str_replace($field->name . "_repeater", "", $inputfield->name);
                foreach ($names as $n => $s) {
                    if (strpos($selector, $n) !== false) {
                        $repeater_name = $n . '_repeater' . $id;
                        $selector = str_replace($n, $repeater_name, $selector);
                    }
                }
            }
            $inputfield->findPagesSelector($selector);
        }
    }
}
);

Here is screen record:

cascade.thumb.gif.c20276d62ebe44abd58bf517d248ebcb.gif

Regards.

  • Like 1

Share this post


Link to post
Share on other sites
22 hours ago, Robin S said:

The dependent selects feature has only ever worked with the selector string option as far as I know.

Sorry, I checked a case outside of a repeater, and you're right. I have dependent selects working, but only after a save. What I had was several page fields outside a repeater that used custom code in ready.php, and a dependent page field inside a repeater, but the containing page was always saved first, so of course the dependent page fields in the repeater worked.

Thanks to your help in another thread:

I can also get dependent selects working inside a repeater if I save after each field is updated.

There doesn't seem to be an option to refresh an individual page field either inside or outside a repeater via an ajax call other than by the selector string option you've mentioned.

 

Share this post


Link to post
Share on other sites
7 hours ago, OLSA said:

thanks @Robin S for your hook example, but also (in my case) I had a problem to save values inside repeaters.

You're right - it doesn't work because the selected pages are lost after save. I remember now that there was an issue with how InputfieldPage and FieldtypePage interpret "page.some_field" when it is used to refer to another Page Reference field: https://github.com/processwire/processwire-issues/issues/479

The thing is that PW has to make some consistent evaluation of what "page" is in this circumstance and it can't really know whether you want page to refer to the edited page or the repeater page. I don't have much time right now but I might come back and explore this more later.

Share this post


Link to post
Share on other sites
3 hours ago, Robin S said:

You're right - it doesn't work because the selected pages are lost after save. I remember now that there was an issue with how InputfieldPage and FieldtypePage interpret "page.some_field" when it is used to refer to another Page Reference field: https://github.com/processwire/processwire-issues/issues/479

Yes, but in my hook example selected pages are not lost and to get that I need to remove selector string settings to hook.

You can see how that's works in my previous post (just added screnshot).

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...