Xonox

Formbuilder: Problem with page select field

Recommended Posts

Hi,

I'm having a problem with a page selection field. I have the following tree set up:

Activities
   - Activity 1
   - Activity 2
   - Activity 3
   - Activity 4

So I created a form where you can select one of the activities on which you would like to participate.

For usability purposes, the form is inserted in each Activity page, so that the user doesn't have to click to get to a form.

I have two problems (let's say the user is inside the "Activity 2" page);

1. Inside the form, where the user can select the activity, the current page is not listed, so the user can select "Activity 1", "Activity 3" and "Activity 4", but not the one in which he is. This one might be a bug.

2. It would be nice that the activity in which he is - Activity 2 - Would be selected by default.

Is there any way that I can accomplish this without a custom markup form?

Thank you.

Share this post


Link to post
Share on other sites

You can probably do this within the InputfieldPage::getSelectablePages hook, that way you can tweak the selectable pages, I'd also try tweaking the value attribute through another field, honestly can't think of the details right now but hope I have given you a hint on a possible solution. 

Share this post


Link to post
Share on other sites
On 11/5/2018 at 5:14 PM, elabx said:

You can probably do this within the InputfieldPage::getSelectablePages hook, that way you can tweak the selectable pages, I'd also try tweaking the value attribute through another field, honestly can't think of the details right now but hope I have given you a hint on a possible solution. 

Hi @elabx,

Thanks for your reply. I really need some help here, working with Hooks.

First, watching the function you showed me, I believe that the responsible bit for not having the self page in the selector is the last part. So it's not a bug, but a feature (not sure why). This are the lines I need to override.:

if($children && $children->has($page)) {
	$children->remove($page); // don't allow page being edited to be selected
}

 

I was playing around with the hooks but I couldn't figure it out. Form builder doesn't have a InputFieldPage Hook, so how am I supposed to hook into it?

The code below must be completely wrong, my apologies, but I'm completely lost here (I have this inside _init.php):

if($page->template == 'activity') {

	// This hook will make sure that the list of pages include self page
	$this->addHookBefore('InputfieldPage::getSelectablePages', function($event) {
		$children = $pages->get('parent=1066');
		return $children;
	});

	$activity_form = $forms->render('activity_form');

}

Can someone point me to the right direction? Thanks!

Alternative

When rendering the select field, add current page and make it selected. Is this possible?

Share this post


Link to post
Share on other sites
33 minutes ago, Xonox said:

Alternative

When rendering the select field, add current page and make it selected. Is this possible?

Thinking about this alternative. This might work better.

So now I have a working code inside _init.php:

// Activity form
if($page->template == 'activity') {

	$forms->addHookBefore('FormBuilderProcessor::renderReady', function($e) {

		$form = $e->arguments(0);
		if($form->name == 'activity_form') {

			// Get Atividade field
			$inputfield = $form->getChildByName('atividade');
			// I NEED TO INSERT A SELECTED OPTION HERE
			// something something = $page->id;

		}

	});

	$activity_form = $forms->render('activity_form');

}

Getting close. Can someone help?

  • Like 1

Share this post


Link to post
Share on other sites
40 minutes ago, Xonox said:

Form builder doesn't have a InputFieldPage Hook, so how am I supposed to hook into it?

Form buiilder is awesome because it does all it's heavy lifting with the same Inputfield classes you use in page edits, so it is indeed an InputfieldPage!

Assuming this is renderd in an iframe try this code (try it in ready.php, I'm really not sure if its the same as doing it on init.php):

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

    //The default PageArray getting selected through your field config
    $defaultSelection = $event->return;
    
    //This is passed through a parameter! 
    //$forms->embed('form-name', ['contextPage' => $page])
    $contextPage = $input->get->contextPage;

    //This would be form-builder page, where it actually renders! 
    //which is not the place the iframe is rendered :)
    $page = $event->arguments('page');
    
    $log->save("debug-pagefield", $page->name);
    $log->save("debug-pagefield", $defaultSelection);
});

 

Share this post


Link to post
Share on other sites
4 minutes ago, Xonox said:

Thinking about this alternative. This might work better.

So now I have a working code inside _init.php:


// Activity form
if($page->template == 'activity') {

	$forms->addHookBefore('FormBuilderProcessor::renderReady', function($e) {

		$form = $e->arguments(0);
		if($form->name == 'activity_form') {

			// Get Atividade field
			$inputfield = $form->getChildByName('atividade');
			// I NEED TO INSERT A SELECTED OPTION HERE
			// something something = $page->id;

		}

	});

	$activity_form = $forms->render('activity_form');

}

Getting close. Can someone help?

Hahah of course! This is super valid, maybe set the value field with the addOption() removeOption() methods (I think what is actually being rendered is an InputfieldSelect, sorry for the misguidance😞

https://github.com/processwire/processwire/blob/341342dc5b1c58012ae7cb26cffe2c57cd915552/wire/modules/Inputfield/InputfieldSelect.module#L173

Share this post


Link to post
Share on other sites
39 minutes ago, elabx said:

Hahah of course! This is super valid, maybe set the value field with the addOption() removeOption() methods (I think what is actually being rendered is an InputfieldSelect, sorry for the misguidance😞

So close and yet so far!

if($form->name == 'activity_form') {

	// Get Atividade field
	$inputfield = $form->getChildByName('atividade');
	$page = wire('page');
	$inputfield->addOption($page->id, $page->title, array('selected'));

}

Two problems:

1 - $page = wire('page'); is this the best way to have access to the page id and title inside the hook? Is there a performance issue?

2 - Error on addOption:

Error: Exception: Method InputfieldPage::addOption does not exist or is not callable in this context (in E:\WebServer\clinicadasconchas.pt\wire\core\Wire.php line 519)

#0 E:\WebServer\clinicadasconchas.pt\wire\core\Wire.php(386): ProcessWire\Wire->___callUnknown('addOption', Array)
#1 E:\WebServer\clinicadasconchas.pt\wire\core\WireHooks.php(723): ProcessWire\Wire->_callMethod('___callUnknown', Array)
#2 E:\WebServer\clinicadasconchas.pt\wire\core\Wire.php(442): ProcessWire\WireHooks->runHooks(Object(ProcessWire\InputfieldPage), 'callUnknown', Array)
#3 E:\WebServer\clinicadasconchas.pt\wire\core\Wire.php(445): ProcessWire\Wire->__call('callUnknown', Array)
#4 E:\WebServer\clinicadasconchas.pt\site\assets\cache\FileCompiler\site\templates\_init.php(31): ProcessWire\Wire->__call('addOption', Array)
#5 E:\WebServer\clinicadasconchas.pt\wire\core\WireHooks.php(813): ProcessWire\TemplateFile->{closure}(Object(ProcessWire\HookEvent))
#6 E:\WebServer\clinicadasconchas.pt\wire\core\Wire.php(442): ProcessWire\WireHooks->ru

It looks like it is a InputfieldPage field, and this doesn't have addOption method.

Share this post


Link to post
Share on other sites

Bingo!

In case someone needs it:

// Activity form
if($page->template == 'activity') {

	$forms->addHookBefore('FormBuilderProcessor::renderReady', function($e) {

		$form = $e->arguments(0);
		if($form->name == 'activity_form') {

			$page = wire('page'); // IS THIS RIGHT?
			$selected = array(); // IS THIS RIGHT?
			$selected['selected'] = 'selected'; // IS THIS RIGHT?

			// Get Atividade field
			$inputfield = $form->getChildByName('atividade'); // Get InputfieldPage
			$select_field = $inputfield->getInputField(); // Get the correspondent InputfieldSelect
			$select_field->addOption($page->id, $page->title, $selected); // Add current page as selected option
		}

	});

	$activity_form = $forms->render('activity_form');

}

Thanks for your help @elabx, it made all the difference!

  • Like 1

Share this post


Link to post
Share on other sites

I'd love if someone could come and give an opinion on why InputfieldPage has a getInputfield() method? I though that object was an InputfieldPage, not a Fieldtype. I'll have to take a look with Tracy Debugger later. 

Share this post


Link to post
Share on other sites
11 hours ago, elabx said:

I'd love if someone could come and give an opinion on why InputfieldPage has a getInputfield() method?

InputfieldPage can be seen as a "layered" inputfield. InputfieldPage itself takes care of the basic logic (processing input, rendering contents etc.) but the ui input itself is delegated to another inputfield type (plain select, ASM select, page autocomplete etc.). Since all of the page related logic (outside specific page inputs like autocomplete or pagelistselect) is inside InputfieldPage, the "real" input modules themselves can be used to input other things besides PW pages too since all they have to deal with are options with values and labels.

  • Like 2
  • 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.