Jump to content

Recommended Posts

Posted

Hi folks,

I have a simple PageField set up, which is being used in this instance as a 'Related Articles' area; they can choose (Multiple Pages) which news articles are related then it does something nice front end. The only issue I have is that I'd like to limit the number of articles they can choose (only allowing three, for example) much like you would have in a File field or Image field (Maximum files allowed).

Any thoughts?

Posted

This greatly depends on the inputfield you're using as it's javascript which would solve this. The only thing you could do from pw aka php is stripping additional pages when saving the page.

Posted

I am using the Page field. So I'm guessing there's no option? Seems a little like an oversight, do you think (not to sound as mean as it looks!)?

Posted

I'm talking about the inputfield you choose the page field to use, e.g. Select, ASMSelect, PageListSelect and so on. These all work differently in terms of markup and javascript, so it's understandable that there's no central way to limit the number of selections beyond single / multiple. Single and Multiple pagefields are even mostly using different inputfields. 

Posted

Ah right, I understand. I am using the ASMSelect for multiple pages. I thought, above all, if you have multiple pages you should at least be able to limit the amount you choose.

Posted

You can always strip off additional pages using php, but that's certainly not the best user experience. For the ASM Select you could create a javascript, which does disable all options from the select box if a certain number of pages was selected (and reset if not).

Posted

nice challenge for the evening with a happy end :)

create a javascript file scripts/limitpageselect.js: 

// my field is called "pageselect"
$(window).load(function() {
    if($('#Inputfield_pageselect :selected').length > 4) $('#Inputfield_pageselect').siblings('select').hide();
    $('#Inputfield_pageselect').change(function() {
        if($('#Inputfield_pageselect :selected').length > 4) {
            $(this).siblings('select').hide();
        }
        else {
            $(this).siblings('select').show();
        }
    });
});

and inject this file via hook in /site/ready.php

$wire->addHookAfter("ProcessPageEdit::buildForm", function(HookEvent $event){
    $process = $event->object;
    $page = $process->getPage();

    if($page->template != 'basic-page') return; // set your template name here

    $config = wire('config');
    $config->scripts->append($config->urls->templates . 'scripts/limitpageselect.js');
});

post-2137-0-99193100-1448405819_thumb.gi

  • Like 7
Posted

I wonder if it's better to wrap the whole hook in such a condition:

if($page->template === 'basic-page') {
    $wire->addHookAfter(...)
}
  • Like 2
Posted

The $page variable is only available through the HookEvent, so you cannot dynamically add the hook, besides if you already have the exact instance of the class you want to hook.

Posted

I see, but in ready.php the $page is already determined, isn't it?

This snippet actually works:

// content in ready.php

if ($page->template != 'admin') {
    $wire->addHookAfter("Page::render", function (HookEvent $event) {
        echo <<< HTML
    <script type="text/javascript">alert('Hello world');</script>
HTML;
    });
}

I guess it's because it hooks to Page:: render.

Posted

$page is of the admin template for everything you visit in the backend. But most of the time you're interested in the page your editing and not the "admin page" your on. 

  • Like 1
Posted

hi tpr,

this method works in frontend but not in admin! try

echo $page->id;

it will show "10" for all processpageedit pages... /admin/setup/ would be 22

unfortunately there's a bug in my script: when you save a field with 5 pages it will not remove the select-field because its only called on change of the field. the problem is, that the select-field is injected by jquery by the admin so this does not work:

// my field is called "pageselect"
$(function() {

    $('#Inputfield_pageselect').siblings('select').hide(); // added this line

    $('#Inputfield_pageselect').change(function() {
        if($('#Inputfield_pageselect :selected').length > 4) {
            $(this).siblings('select').hide();
        }
        else {
            $(this).siblings('select').show();
        }
    });
});

maybe it would work if the script was loaded at the very last of all scripts?

post-2137-0-12119600-1448442893_thumb.pn

how could i achieve that?

Posted

Hi BernhardB,

I have a small module that injects a script tag right before </body>. Here's the relevant lines

	public function init() {

		$this->addHookAfter('Page::render', $this, 'addInlineScript'); 

	}

	public function addInlineScript($event) {

		$page = $event->object;

		if ($page->template->name !== "admin" && $page->inlineScript) {

			$event->return = str_replace("</body>", $page->inlineScript . "</body>", $event->return);

		}

	}

You can adjust that to your situation. Hope it helps.

  • Like 1
Posted

@LostKobraKai

Wouldn't you actually need window.onload or $(window).load for that?

$(document).ready fires when the DOM is ready and does not wait for all resources like scripts/images.

See here and here.

  • Like 1
Posted

thank you!

i was already using document.ready (short syntax) - gebeer was right, both injecting the JS via str_replace(</body> and loading the script via window.onload worked!

i updated the code above so it should be working now.

Posted

Some improvements in the JS:

$(window).load(function () {

    var fieldName = 'tags_recipe',  // add field name here
        limit = 5,  // set limit here
        asmSelector = '#Inputfield_' + fieldName;

    $(asmSelector).on('change limitItems', function () {
        var obj = $(this).parent().find('.asmSelect');
        $(this).find(':selected').length >= limit ? obj.attr('disabled', 1) : obj.removeAttr('disabled');
    });

    $(asmSelector).trigger('limitItems');
});

What would be nice is to add the "limit" in the backend to the asmSelect using a "data-limit" attribute and then let JavaScript do its part on all asmSelects which have data-limit set.

  • Like 5
  • 2 years later...
Posted

It's done, will be added to the next aos update. I've borrowed some code from @Robin S modules (thanks!) as I haven't added config inputs to fields so far.

In fact I totally forgot about this asmSelect snippet of mine, thanks for the reminder :)

 

limitasmselect01.png

limitasmselect.gif

  • Like 5
  • Thanks 1
Posted
23 minutes ago, tpr said:

It's done, will be added to the next aos update.

Awesome!

Do you reckon you could do something similar for Page Autocomplete? :)

Posted
6 hours ago, Robin S said:

Do you reckon you could do something similar for Page Autocomplete?

I saw this follow-up question coming, ? I think that's also doable, will check that later. I reckon the same question is about to emerge for the rest of the PageField types, isn't it? ?

  • Like 1
  • Haha 1

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
×
×
  • Create New...