Jump to content

Dynamic Options


Robin S
 Share

Recommended Posts

A Fieldtype for dynamic options that are generated at runtime via a hook.

Configuration

Inputfield type

You can choose from a range of inputfield types on the Details tab of a Dynamic Options field. Your field will return a string or an array depending on if the selected input field type is for "single item selection" or "multiple item selection".

Maximum number of items

You can define a maximum number of items the field is allowed to contain. The core inputfields supported by this module will become disabled once the limit is reached. This option is only applicable if you have selected an inputfield type that is for multiple item selection.

Format as Pagefile/Pageimage object(s)

If the field will store paths/URLs to Pagefiles/Pageimages then you can enable this option to have the formatted value be a Pagefile/Pageimage object for "single" fields or an array of Pagefile/Pageimage objects for "multiple" fields.

There is a related Select Images inputfield module that allows you to visually select image thumbnails.

Defining selectable options

Selectable options for a Dynamic Options field should be set in a FieldtypeDynamicOptions::getSelectableOptions hook in /site/ready.php. The hook should return an array of options as 'value' => 'label'.

An example hook is shown on the Details tab of a Dynamic Options field:

$wire->addHookAfter('FieldtypeDynamicOptions::getSelectableOptions', function(HookEvent $event) {
    // The page being edited
    $page = $event->arguments(0);
    // The Dynamic Options field
    $field = $event->arguments(1);
    if($field->name === 'your_field_name') {
        $event->return = [
            'red' => 'Red',
            'green' => 'Green',
            'blue' => 'Blue',
        ];
    }
});

Formatted value

If a Dynamic Options field uses a "single" input type then its formatted value is a string, and if it uses a "multiple" input type then its formatted value is an array. The unformatted value of a Dynamic Options field is always an array.

Also see the Configuration section above for description of an option to have the formatted value be Pagefile/Pageimage object(s).

Examples of possible uses

dynamic-options

$wire->addHookAfter('FieldtypeDynamicOptions::getSelectableOptions', function(HookEvent $event) {
    // The page being edited
    $page = $event->arguments(0);
    // The Dynamic Options field
    $field = $event->arguments(1);

    // Select from the "files" field on the page
    if($field->name === 'select_files') {
        $options = [];
        foreach($page->files as $file) {
            // Value is basename, label is description if one exists
            $options[$file->basename] = $file->get('description|basename');
        }
        $event->return = $options;
    }

    // Select from files in a folder
    if($field->name === 'select_folder_files') {
        $options = [];
        $path = $event->wire()->config->paths->root . 'my-folder/';
        $files = $event->wire()->files->find($path);
        foreach($files as $file) {
            // Value is full path, label is basename
            $options[$file] = str_replace($path, '', $file);
        }
        $event->return = $options;
    }

    // Select from non-system templates
    if($field->name === 'select_template') {
        $options = [];
        foreach($event->wire()->templates as $template) {
            if($template->flags & Template::flagSystem) continue;
            $options[$template->id] = $template->name;
        }
        $event->return = $options;
    }

    // Select from non-system fields
    if($field->name === 'select_field') {
        $options = [];
        foreach($event->wire()->fields as $field) {
            if($field->flags & Field::flagSystem) continue;
            $options[$field->id] = $field->name;
        }
        $event->return = $options;
    }

    // Select from FormBuilder forms
    if($field->name === 'select_formbuilder_form') {
        $form_names = $event->wire()->forms->getFormNames();
        // Use form names as both keys and values
        $event->return = array_combine($form_names, $form_names);
    }

});
  • Like 21
Link to comment
Share on other sites

v0.1.3 released. This version adds options to set a limit to the number of items that may be selected. When the limit is reached the supported core "multiple" inputfields become disabled. It  adds an option for the formatted value to be Pagefile/Pageimage object(s) where that would be relevant. And it integrates with the newly released Select Images module to create a kind of "image reference" field. See the updated readme for more detail.

 

  • Like 3
Link to comment
Share on other sites

  • 1 year later...

Thanks for this great module!  I was wondering if it would be possible to add support for making it work with custom image/file fields templates?

At the moment the option to enable it is crossed out in FieldtypeFile modeule settings (in PW 3.0.211 dev).

Link to comment
Share on other sites

8 hours ago, LMD said:

At the moment the option to enable it is crossed out in FieldtypeFile modeule settings (in PW 3.0.211 dev).

Probably it applies to the strikethrough to any non-core fieldtypes because it can't guarantee 100% compatibility. Did you try ticking the checkbox anyway? It seems to work when I did some quick testing.

Link to comment
Share on other sites

13 hours ago, Robin S said:

Probably it applies to the strikethrough to any non-core fieldtypes because it can't guarantee 100% compatibility. Did you try ticking the checkbox anyway? It seems to work when I did some quick testing.

Well, this is embarassing, I did actually try it yesterday and it didn't work, but I tried again this morning and it works just fine now.  I don't know what changed  - maybe I forgot to save something before.

Sorry about that!

  • Like 1
Link to comment
Share on other sites

  • 1 month later...

Update:  SOLVED!

Never mind, I had moved a bunch of hooks to admin.php, including the DynamicOptions hook, which is why it stopped working on the frontend.  I have put the hook back in ready.php and works as expected.  Of course that makes perfect sense in retrospect.

[--- Snipped description of the problem, it was a wild goose chase! --]

Edited by LMD
I solved the issue, it was me... I was the problem!
  • Like 1
Link to comment
Share on other sites

Not a problem, this time, but an FYI and a solution in case anybody needs it.

When using a Dynamic Options field as an images/files custom field, the 'page' value of 'arguments(0)' is not the page being edited, but instead it's a dummy page used for the 'field-fieldname' template.

If the actual page is required for some logic (a need I had), then this poses an issue... but there is a solution!

In your 'getSelectableOptions' hook, do the following:

$wire->addHookAfter('FieldtypeDynamicOptions::getSelectableOptions', function(HookEvent $event) {
    $page = $event->arguments(0); // Page data (which will be wrong for our specific use case)
    $field = $event->arguments(1); // Field data

    // 'foo' is an images custom field
    if ($field->name === 'foo') {
		/* Get the page -- where we get page from will be different in the admin (edit) and frontend.*/
        $page = $this->page; // the current page route (sufficient for the frontend)

		/* However, in the admin edit page (check the process) */
        if ($page->process === 'ProcessPageEdit') {
			// Get the id of page being edited from $input and then use that to fetch the page
            $page = $this->pages->get($this->input->get('id', 'int'));
        }

        $options = []; // empty array to return if no valid page is found

		// If it is a valid id... continue as usual, using the $page var
        if ($page->id) {
            if ($page->template->name === 'gallery') {
                $options = ['foo' => "Foo", 'bar' => "Bar"];
            } else {
                $options = ['lorem' => "Lorem", 'ipsum' => "Ipsum"];
            }
        }

        $event->return = $options;
    }

	// ... other fields as required can use the $page from args
});

No idea if there is a different way, but this method is fairly simple, besides, it's not going to be a common issue.

Hope this helps somebody.

Here's the Tracy dump of the custom field "page" for the curious:

ProcessWire\DefaultPage
	id: 0
	name: ''
	parent: ''
	status: 'corrupted'
	template: 'field-images'
	caption: ''
    foo: => ''
	data: array
    	'caption' => ''
		'foo' => ''

 

  • Like 1
Link to comment
Share on other sites

  • 9 months later...
6 hours ago, eydun said:

Have you been able to make it work in a combo-field?

No, this module is a fieldtype, and Combo is also a fieldtype. There isn't such a thing as one fieldtype module working inside another fieldtype module.

But you can easily add both a Dynamic Options field and a Combo field to your template so that you can use them together. You can even have the Dynamic Options inputfield adjacent to any particular Combo subfield in Page Edit thanks to the "Custom form placement" option for Combo subfields:

image.png.7f6395605d11cb00f39ef1cd4a2e5746.png

  • Thanks 1
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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...