http://www.perlmonks.org?node_id=701312

rustycar has asked for the wisdom of the Perl Monks concerning the following question:

Sorry in advance for such a long post here...

I'm using select() to select an item from a 'select' list (duh! :-) - but I do not know ahead of time what the names of said items are.

So, I wrote something like this:
my $ans = 1; # or whatever. while ($ans) { %pickme = ( n => 1 ); #yes, this should be outside the while. So s +ue me ;-) $ans = $mech->select( 'server', \%pickme ); if ($ans) { $inputobj = $mech->current_form()->find_input( 'remove', 'subm +it'); die 'argh! Cannot find delete button on the iSCSI Access page! +' unless $inputobj; $ans = $mech->click_button( input => $inputobj ); } } print "Done! Now, accept the empty list\n"; # ok, now accept a (hopefully) empty list of allowed accessors $inputobj = $mech->current_form()->find_input( 'accept', 'submit'); die 'argh! Cannot find Accept button on the iSCSI Access page!' unless + $inputobj; $ans = $mech->click_button( input => $inputobj );
However, it turns out that select will ALWAYS think that it can select entry 1, even if the list is empty. In other words, even when the html looks like this:
<td> <input type="hidden" name="serverList" value=""> <select size="10" name="server" style="width: 330px"> </select> </td>
The above code will get '1' back from select and go running on forever. Not a good thing...

I discovered that if entry 2 didn't exist, and you tried to select THAT entry you'd get an appropriate error, so I ended up with this as a workaround:
while ($ans) { %pickme = ( n => 2 ); eval { $ans = $mech->select( 'server', \%pickme ); }; if ($ans eq 1) { $inputobj = $mech->current_form()->find_input( 'remove', 'subm +it'); die 'argh! Cannot find delete button on the iSCSI Access page! +' unless $inputobj; $ans = $mech->click_button( input => $inputobj ); } else { $ans = 0; } } %pickme = ( n => 1 ); $ans = $mech->select( 'server', \%pickme ); $inputobj = $mech->current_form()->find_input( 'remove', 'submit'); die 'argh! Cannot find delete button on the iSCSI Access page!' unless + $inputobj; $ans = $mech->click_button( input => $inputobj ); print "Done! Now, accept the empty list\n"; # ok, now accept a (hopefully) empty list of allowed accessors $inputobj = $mech->current_form()->find_input( 'accept', 'submit'); die 'argh! Cannot find Accept button on the iSCSI Access page!' unless + $inputobj; $ans = $mech->click_button( input => $inputobj );
It seems to me that the first form should have worked (see the Mechanize page under select() for details of why - won't bore everyone here with that), so I'm looking at the Mechanize and Form code to see why it allows a 'select' of 1 when there are no items.

I've looked at WWW::Mechanize, and the issue seems to be in Form instead. Here is the section that seems to be involved here:
for (@{$self->{menu}}) { if ((defined($val) && defined($_->{value}) && $val eq $_-> +{value}) || (!defined($val) && !defined($_->{value})) ) { $cur = $i; $disabled = $_->{disabled}; last unless $disabled; } $i++; }
When there is nothing in the select list, the above test still passes! I note, when stepping through the code, that if I print $val when I'm looking at the 'big if' above, I get a blank line, BUT defined($val) is true!

So, am I just confused, is the above test wrong, is my code wrong, or ???

(Conclusion: the HTML is wrong - its illegal to have a select with no option. You should have a single empty option, and detect that its an empty option (I'll have to RTFM for how to do that, but that's just Fine :-)

Thanks!

Final comment - thanks to Hermit (psini for his/her help - and sorry for not thinking to RTFM on how HTTP select fields work, once the comment was made (too focussed on Mechanize::select and figuring out how to get around having no (obvious) way to tell when there's nothing there....

Anyway, I consider this thread finished (and now I know what bug to file with the authors). I've modified the subject, at the suggestion of ambrus, to make it better. Thanks again!

Replies are listed 'Best First'.
Re: Is this a bug in select(), or am I just confused? (or something else)
by ikegami (Patriarch) on Jul 31, 2008 at 02:21 UTC
    It's illegal to have a SELECT with no OPTION, so this appears to be a case of GIGO at the very least.
      Ah, interesting. What happens is that the page displays an empty box upon first startup. Then, when you click the 'add' button you can add items into the box. Or, once you have items listed in the box, you can select them (one at a time) and click on the 'delete' button. Sounds like the empty box must not have an empty 'select' tag, then once there are items to select then they need to add the appropriate <select> tags. Hmm. Too bad empty select is illegal! :-)

      If this is incorrect, please let me know, as I'll be sending that info (probably late tomorrow) to the authors of the html to have them fix it.

      And sorry for not searching to find out that empty select's are evil :-)

      (I guess this STILL leaves the question of what $mech->select() should do when there is nothing to select. Seems like it should still say 'nothing to do' and return 0 - oh, well.)

        You can't have an empty SELECT, but you can have a SELECT with a single empty OPTION. When user adds an item you should check if the first option is empty and delete it before adding the new option.

        Rule One: "Do not act incautiously when confronting a little bald wrinkly smiling man."