Jump to content
a-ok

PageField – limit number of choices

Recommended Posts

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?

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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!)?

Share this post


Link to post
Share on other sites

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. 

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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).

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

$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

Share this post


Link to post
Share on other sites

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?

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Just use $(document).ready(function(){ … }); around your code, so it's not executed before the whole dom is loaded.

Share this post


Link to post
Share on other sites

@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

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

@tpr - have you considered adding this functionality to AOS?

Or maybe a @Robin S "limit" special module :)

  • Like 2

Share this post


Link to post
Share on other sites

I haven't yet but I'll give a try. 

  • Like 4

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
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? :)

Share this post


Link to post
Share on other sites
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

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.

  • Similar Content

    • By louisstephens
      So I ran into a very strange issue today. I have a template with a pagetable and I went to add an item to it, when I went to select an image (for an image field) the page instantly threw up an error
      "ProcessPageSearchLive: No search specified"
      The page's content also switched to the image attached. This all worked perfectly last week (local mamp box). Has anyone experienced this before, and how did you solve it?
       

    • By Pip
      Hi everyone, 
      Is there a way for us to replicate the "http://mydomain.com/processwire/page/edit/?id=xxx" and change the template to match my site template? 
      I'm terribly happy with the admin / backend page edit. It covers literaly everything I want to empower my non super admin user in updating pages such as validation, repeater management, file upload. 
      I wish not to allow the users to see the backend for both security and aesthetic reasons. 
      Thanks and hope to hear from you soon. 
       
    • By snck
      Hi there,
      I have a problem constructing a selector that finds all pages that refer to pages with a specific template.
      I have pages using an event template and I want to show events based on a specific context. In this example I want to filter the results and only show event pages that relate to a specific template (exhibitions) in their page field related_pages.
      What I tried:
      $events = $pages->find("template=event, related_pages.template.name=exhibition"); Unfortunately it does not work (0 results).
      Same with this:
      $events = $pages->find("template=event, related_pages=[template.name=exhibition]"); At the moment I am helping myself with the following lines, but I have a strong feeling that there is a more efficient solution:
      $events = $pages->find("template=event"); foreach($events as $event){ if(!count($event->related_pages->find("template=exhibition"))){ $events->remove($event); } }  
      I really hope that one of you can help me out.
      Thanks in advance!
      Flo
    • By EyeDentify
      Hello dear PW gurus.

      I have stumbled over a strange error that i all of sudden got when trying to upload an image to a images field on a page.
      There where images allready stored in the field that i wanted to keep, but during the upload the error apear and after that all images are gone from the field and i can´t upload any, i just get the error every time.
      I am running ProcessWire 3.0.153 dev.
      Update:
      After looking in the assets folder i find the folder for the page and the image files seems to be there including the ones i tried to upload when the error occured.
      But they don´t show up in the images field in the page editor.
       
      The error reported:
       
      SQLSTATE[01000]: Warning: 1265 Data truncated for column 'ratio' at row 1 And here is a screenshot of the event:

      The TracyDebugger Error reporting:

      I hope you fine folks could point me in a direction.
      But it seems our old pal set_time_limit() is back.

      Regards, EyeDentify
    • By Spyros
      Hello
      I'm having a strange issue with the $page->find(), for some reason I'm missing some of the pages from the results. I found then that I was missing all the pages with the same "PAGE NAME". Is it a bug or am I missing something?
      PS 
      If I change the "PAGE NAME" of one of the missing ones then I'm retrieving the page without any problem.
      Thank you
×
×
  • Create New...