Jump to content

Fieldtype: Select (AKA Drop Down)


Hani

Recommended Posts

I noticed that although there's an InputfieldSelect module, there wasn't a FieldtypeSelect that would produce a drop down list (via a "select" input) that would allow you to define a list of options in the field's configuration.  (Somewhere in this forum, I saw that the "Page" fieldtype was suggested to do this - and it works - but it didn't seem as easy as it should be.)

So, I went ahead and created a module to do it!

After installing, you'll have a new "Select" fieldtype that will allow you to define the items you'd like in the drop down.  You'll be able to define these options in a text box on the field's configuration screen.  Just put each option on it's own line.

Hope this helps someone out!

Let me know if you experience any issues with it, find any bugs or if you have some ideas on improvement.

EDIT: The module is now on github: https://github.com/Hani79/Processwire_FieldType_Select_Drop_Down  (Thanks for the prompt to put it up there, Soma.)

  • Like 5
Link to comment
Share on other sites

Hi, nice plugin :)

Just one suggestion: Often the value administrator sees isn't the same one you want to have saved in your db (for code purposes). So it would be nice to have option to create value-label combo, e.g.:

In your $field->options, you have

1:=Eat your hair
2:=Eat your eyes
3:=Eat your world

and then, when generating the field, you use numbers as option values and the eat strings as 'labels' shown in select

Note: I selected delphi assign symbol (:=), because it offers nice readbility, but let's administrators use ':' '=' in their labels – but combination of both (:=) just doesn't appear in natural language (only in =:haxx0rz:=) ;D

Link to comment
Share on other sites

Hani, nice work with this fieldtype, as well as the state select one. I tried both out and they work well!

I should explain why PW doesn't implement selects in the manner that this plugin does. This plugin stores values are not normalized; it uses the database as a non-relational flat file. One of the resulting issues if that if you need to go back and change or remove one of the options, your change will not affect any values already present, ultimately corrupting the data. This could be a problem in large scale usage. PW uses a Page fieldtype to achieve the same thing (albeit with a little more effort) so as to avoid the issues mentioned above and others. But the reality is that many sites are not working at that scale or affected by the drawbacks, so I think your Select fieldtype and it's simpler administration will be a welcome solution for many. Thank you for putting it together. I know you likely produced this fieldtype with an understanding of the compromises, so just wanted to highlight the considerations for others that may researching which solution to use in a given situation. I can certainly think of situations where I will use your fieldtype.

Down into the actual fieldtype's code, I have a few suggestions for you:

In your getInputfield() method, these two lines are not necessary:

$inputfield->attr('name', $field->name);
$inputfield->class = $this->className();

On my installation, the submitted values were getting stored with the "\n" as part of them. In your getInputfield() method, I recommend trimming the value before sending it to $inputfield->addOption(), i.e.

foreach($options as $option) {
   $option = trim($option);
   if(!strlen($option)) continue;
   $inputfield->addOption($option);
}

When I edited a page with this fieldtype, it already had a value selected. I recommend adding a blank option at the top of the select so that the first value isn't automatically selected (again, in your getInputfield() method):

$inputfield = $this->modules->get('InputfieldSelect');
$inputfield->addOption(''); // blank or unselected option

In your sanitizeValue() method, you may want to consider adding something that checks that the value is actually one of the allowed options. This is optional, but just an extra if you want it. There is some overhead in doing it, so you may decide it's worthwhile or not depending on what you want. But here's one way you could do it:

<?php
public function sanitizeValue(Page $page, Field $field, $value) {

    // remove any leading/trailing whitespace
    $value = trim($value); 

    // If value isn't present in the select_options string, surrounded by CRLFs or CRs then it's not valid.
    // We also allow for match at beginning/end of select_options, as well as optional spaces in the select_options string
    // before and after the CRLF/CR that separate the options in the string.
    if(!preg_match('/(^|[\r\n]) *' . preg_quote($value, '/') . ' *([\r\n]+|$)/', $field->select_options)) $value = '';

    return $value;
}
  • Like 1
Link to comment
Share on other sites

Thanks for the feedback guys!

Ryan - you bring up a great point that this fieldtype results in non-relational data being stored in the database.  This could potentially cause problems for people down the road - so I am really glad you brought it up (I failed to mention it).  But your point that some folks may be okay with that drawback because they're running smaller-scale websites.  For large scale usage, I would agree with you that the Page fieldtype is the way to go.  :)

Also, thanks for the code tips!  I've implemented those changes (with a few tweaks because of the additional functionality suggested by Adam).

Adam - adding value/label pairs was actually something I thought about.  But for my immediate needs, I decided to skip it.  However, I decided to take a stab at it right now and found that for some reason, the data isn't being saved to the database for that field.  I've attached the updated module.  Ryan - do you have any idea why it isn't saving the selected option to the database?  I dived into the code (processInput, savePageField, etc.) but couldn't seem to find out what was going on.  (No rush on this issue for me - whenever you get some time.)

Thanks, guys!

EDIT: Removed the attachment.  Module is on github.  Link in first post.

Link to comment
Share on other sites

Hani, thanks for your continued updates. The sanitizeValue() function is most likely the reason why it's not saving values when you use the value/label ... the snippet I posted before wasn't coded with that in mind, so it would have to be updated to account for the change. While I haven't yet tested it, I'm thinking this might do it (to replace the preg_match currently in the sanitizeValue function):

if(!preg_match('/(^|[\r\n]) *' . preg_quote($value, '/') . ' *(:=|[\r\n]+|$)/', $field->select_options)) $value = '';
Link to comment
Share on other sites

  • 2 months later...

Just for info, this works and saves the dropdown if you use ryan's amended preg_match line in the module and you're interested in a key -> value dropdown list.

One future improvement I'd like to see is if there could be a setting to force the user to select something from the list, otherwise the page will throw an error message when saved. There are plenty of times when you want something to be filled out and select lists are no different.

Only trouble is I wouldn't know where to begin with that. Yet. I'm learning slowly but surely ;)

Link to comment
Share on other sites

One future improvement I'd like to see is if there could be a setting to force the user to select something from the list, otherwise the page will throw an error message when saved. There are plenty of times when you want something to be filled out and select lists are no different.

True. That would be useful all around. If I remember correctly there is no way to say which fields are required at all. This could be great option on many fields, not just this one. I remember Ryan mentioned something about this, but not sure what was it?

Link to comment
Share on other sites

Actually I think if you set $config->advanced = true in your /site/config.php file, then you'll get a 'required' option with most fieldtypes. The only problem is that this has to be implemented by the fieldtype module, and it's not implemented by all of them. But as we get closer to wrapping up 2.1, it seems like this is one thing that should probably be finalized in this version (and taken out of advanced mode).

Link to comment
Share on other sites

  • 7 months later...

I'm currently working on an online magazine for a site and I have to provide an interface an editor can use to publish new issues. I had hoped i could make it simple and allow all the articles to reside loose in the issue folder:

Magazine

April 2012
Article 1
Article 2
Article 3
etc.

And organize the presentation by having a drop down menu in the magazine page template to allow the editor to select a section : 1-Feature 2-Health 3-lighter side

Then in the table of contents I could list all articles in sections: Feature articles, health articles and so on. Would this module do the job or is this meant to be used by site visitors?

Link to comment
Share on other sites

I think I answered my own question. I installed the module and tweaked it with Ryan's fix to get the value to save.

I haven't been able to get it to display the articles in the proper order but that's just because I have no idea what I'm doing. It does look like it will work though.

Link to comment
Share on other sites

OK I'm still having a problem with this. I can get the articles to display BUT if there is no article associated with a section (determined by the drop down menu) I don't want the heading to appear in the markup. I can't get that to work.

To illustrate lets say I have 3 sections defined in the drop down:

1:=Feature article

2:=Health

3:=lighter side

in this month's edition of the magazine I have 3 feature articles, 0 health articles and 1 lighter side article. In the markup on the site I have headings <h2> for each section but if there is no article for a particular section I don't want that heading to appear so for this month there would be a heading for feature article with 3 articles listed under it, and a heading for lighter side with 1 article listed. Health won't appear because there is no article this month. Next month there may be one so at that point the heading will appear above the article in that section.

Right now I can get the articles to appear in each section but even if there is no article in Health, the heading shows up, I assume because the section exists in the drop down. Can I get around that?

I have been wracking my brain over this for a couple of hours, gave up, had a couple of drinks and then returned to it. If none of this makes sense, the drinks may be why.

Link to comment
Share on other sites

And organize the presentation by having a drop down menu in the magazine page template to allow the editor to select a section : 1-Feature 2-Health 3-lighter side

Then in the table of contents I could list all articles in sections: Feature articles, health articles and so on. Would this module do the job or is this meant to be used by site visitors?

I think that for this kind of features you don't want to use this module, but native pw-implementation using Page-field. Create hidden page called "sections", under that page you have three pages: feature, health and lighter side. After that you create page-field which allows pages under that "sections" page.

This way you get real relations between sections and articles, you can easily scale (remove and add sections), it even works when you later decide that one article can be in multiple sections etc...

Also it allows easily to change inputfield, so you can have dropdown, radio buttons, pagelist, asmSelect, checkboxes, autocomplete... whatever is required.

Link to comment
Share on other sites

I think that for this kind of features you don't want to use this module, but native pw-implementation using Page-field. Create hidden page called "sections", under that page you have three pages: feature, health and lighter side. After that you create page-field which allows pages under that "sections" page.

This way you get real relations between sections and articles, you can easily scale (remove and add sections), it even works when you later decide that one article can be in multiple sections etc...

Also it allows easily to change inputfield, so you can have dropdown, radio buttons, pagelist, asmSelect, checkboxes, autocomplete... whatever is required.

Thanks Apeisa under ordinary circumstances I think you'd be right. I deal with clients who need me to set up their email, some don't even know how to check email. What's a URL? What is a domain name and how is it different from hosting? etc. etc. Things need to be verrrry simple, which is what I like about this module. All pages associated with an edition of the magazine go inside a parent directory for that issue. Sections are determined by an easy drop down selection. Asking the future site editor to create hidden pages for sections will result in me spending hours on the phone walking them through what a hidden page is and how to make it. :)

I got this module to work. It displays article links under the right section heading just like a dream. My only problem now is that headings display even when there are no articles in the section.

if I use

	$articles = $page->children;
	$features = $articles->find("magazine_section=A");
		if ($features)
		echo "<h2>Feature Articles</h2>\n<ul>";
			 foreach($features as $feature) {
			 echo "<li><a href='{$feature->url}'>{$feature->article_title}</a></li>\n";
}	
echo "</ul>\n";

It displays articles correctly but shows the heading even if no articles exist. If I use

  $articles = $page->children;
	$features = $articles->get("magazine_section=A");
		if ($features)
		echo "<h2>Feature Articles</h2>\n<ul>";
			 foreach($features as $feature) {
			 echo "<li><a href='{$feature->url}'>{$feature->article_title}</a></li>\n";
}	
echo "</ul>\n";

It hides the heading if no articles are present for that section but if there are articles all it displays is a list of bullets, no links. My code could be completely wrong but it's close so i have hope that this module will work.

Link to comment
Share on other sites

Apeisa is right and it's by far the best approach. Don't worry even simple minded non tech people will understand how to add a page that will serve as a category. It doesn't need to be hidden, only the "/catergory/" page that holds the categories. It can't get any simpler than having a page called Categeory, then click it and click "new". Voila. You can even setup the template to only allow "category" templates as childrens under the tab "Family" in the template settings.

After that you can in future even add fields like description and images, so the category could have meta data displayed. And as apeisa mentioned it even allows for multiple categories selected, the page inputfield will allow very versatile usage. There's a real connection that is most flexible. Your solution is very limited and unflexible and to my understanding even more complicated to the site admin to add a weird 1:=Label and it allows for errors very easy. No way to screw up with the page select approach.

Anyway you could try this with your code, it was a real mess I guess ;) no problem this "should" work:

$features = $page->children("magazine_section=A");
if ($features->count() > 0){
echo "<h2>Feature Articles</h2>\n<ul>";
foreach($features as $feature) {
	echo "\n\t<li><a href='{$feature->url}'>{$feature->article_title}</a></li>\n";
}
echo "</ul>\n";
}		

  • Like 1
Link to comment
Share on other sites

Thanks Apeisa under ordinary circumstances I think you'd be right. I deal with clients who need me to set up their email, some don't even know how to check email. What's a URL? What is a domain name and how is it different from hosting? etc. etc. Things need to be verrrry simple, which is what I like about this module. All pages associated with an edition of the magazine go inside a parent directory for that issue. Sections are determined by an easy drop down selection.

I think you have misunderstood the resulting UI here. For your end user, it will be exactly same experience. Easy drop down selection for section, and each article is directly under the magazine page.

Link to comment
Share on other sites

I think you have misunderstood the resulting UI here. For your end user, it will be exactly same experience. Easy drop down selection for section, and each article is directly under the magazine page.

You're right. I couldn't get my head around it. Seemed overly complicated for what I needed. probably not if I'd looked at it from the start and taken the time to do it "properly". I'll have to explore it more.

Hey Digitex, check this out! This brand new feature makes creating sections a breeze even for dumbest users alive :) And it works with all your favorite page inputfield flavours. Update now and get it absolutely free of charge! :P

Processwire's being developed so fast that even if you have the latest of everything when you start a project, by the time you get half way finished there are new features ready that would have made your job easier. I tackle problems as they come up so when it did I looked for the simplest solution and this module seemed like it. It would be nice to see it developed further to have the power and flexibility of the Page-field approach with the ease of implementation this module allows.

That's just the opinion of someone who's PHP skills hover around the "me Tarzan you $page" level.

Link to comment
Share on other sites

  • 2 weeks later...

I think that for this kind of features you don't want to use this module, but native pw-implementation using Page-field. Create hidden page called "sections", under that page you have three pages: feature, health and lighter side. After that you create page-field which allows pages under that "sections" page.

This way you get real relations between sections and articles, you can easily scale (remove and add sections), it even works when you later decide that one article can be in multiple sections etc...

Also it allows easily to change inputfield, so you can have dropdown, radio buttons, pagelist, asmSelect, checkboxes, autocomplete... whatever is required.

So this thread (http://processwire.com/talk/topic/745-module-want-related-pages/) could also use this approach - very similarly, right?

If so, then this [iS] the best way to go. If not, then i'm even more confused :). But i'm pretty sure you're going to say that it COULD indeed be used as a solution to the thread aforementioned... (or at least as a good alternative).

[ I SURE as heck wished that i wouldn't have gotten SO invested into taxonomies, tags, categories, etc... and just stuck with "a page is a page is a page" before I got SUCKED into the wormhole called WordPress and of the like ... ah, but live-n-learn, I will - live-n-learn! ]

Link to comment
Share on other sites

Thanks for developing this, Hani. This solved my problem. :lol:

On another note, I wasn't able to figure out how to use the Radio inputfield. I first tried doing that but radio doesn't show up as an option for fields (though it shows up as an installed module).

Link to comment
Share on other sites

Tinacious--you'll see Radios as an option with Page reference fields. All single/multiple selection in ProcessWire is handled with the Page reference field. You'll see it when you create a new field and it asks you to choose the type: choose Page.

Link to comment
Share on other sites

  • 3 months later...

I stumbled on this only now. Never had to create radios or dropdowns in PW before :)

I want to create a simple m/f choice with a radio button. How should I do it? Create two pages, one "masculine" and one "feminine" under a parent "sex"? It feels so overkill to me, even after being used to the PW way. I wonder if it wouldn't make more sense to have those two simple fields in the core.

Link to comment
Share on other sites

That is how I would do it. In that particular case (male / female choice) it maybe feels overkill, since that is pretty much stable selection (you probably don't have third sex coming etc). Usually this kind of selection can be done with boolean checkbox, but I agree that would not be good in this case.

But actually that is not so bad. Usually I have the hidden /tools/ page and under that I would have the "sex" with "male" and "female" children. For this kind of selections I have one generic "reference" template. Creating the pages takes about 1 minute, so it's not that bad overkill :)

If you would like to go the real "overkill" route, then you would create male/female fieldtype/inputfield combo.

Link to comment
Share on other sites

Yep, that's what I did. Of course it works, there's no reason not to. And it took one minute to create, also true :)

But I'm looking at it from the newcomer view... If I work with PW for some time already, and got pretty used to it's way of doing things. I can imagine that this should feel very strange to someone that has the need for something like this on the first project.

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
  • Recently Browsing   0 members

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