Problem/Motivation
A required Country field does not match core's "List (text)" field's "Select list" widget required field behavior.
When a List (text) field is marked required and the form display widget chosen is "Select list", then the "- Select a value -" option is shown. A required Country field does not show this option.

Note: If this field is overlooked, the user will inadvertently submit a value they did not explicitly choose and may be incorrect.
Original report by edsoncarlos
Add "Select" option if field is required
Add "Select" option in the country list if field is required. But a country still must be selected.
| Comment | File | Size | Author |
|---|---|---|---|
| #73 | 2995992-2_0_x-no-default-user-must-select-73.patch | 23.78 KB | grevil |
| #66 | 2995992-66-with-patch-select-brazil.png | 85.27 KB | dww |
| #66 | 2995992-66-with-patch-validation-error.png | 54.1 KB | dww |
| #66 | 2995992-66-with-patch.png | 44.02 KB | dww |
| #66 | 2995992-66-no-patch.png | 71.04 KB | dww |
Issue fork address-2995992
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
edsoncarlos commentedComment #3
bojanz commentedThere's a patch here, but the formatting looks suspicious, and there are no tests. Updating status.
Comment #4
jcandan commentedUpdated the issue summary to make the case that this is Drupal core default behavior and should be addressed.
Comment #5
johnpicozziA client asked for the country address field which is required on all our forms to not default to Afghanistan, as shown above. I updated to the latest version of Address (1.7.0) in hopes this would have been resolved. I found that the patch still applied cleanly and provided the desired effect. I second the call to getting this addressed.
Comment #6
jcandan commentedI am currently working to re-roll the patch following Coding Standards and with tests. Should be up soon, but I am having issues getting
FunctionalJavascripttests to play nicely with Lando.Comment #7
jcandan commentedRe-rolling patch. This is just added test coverage for this issue.
Comment #8
jcandan commentedOkay, that test passed. It was not supposed to. I think I have resolved my local FunctionalJavascript testing woes. I'll circle back around tomorrow morning.
Comment #9
johnpicozzi@jcandan - Once you are set let me know and I can test for you.
Comment #10
jcandan commentedRe-rolled patch. It is a surprisingly simple fix. This patch includes test changes which fail if the fix is not applied.
I was finally able to run
FunctionalJavascripttesting locally. It turns out that the reason the test passed, before the fix was applied, was that theassertOptionSelectedwould not fail. This was because it did not find an empty value option, and therefore never asserted any option was selected. I have addressed this gap in this patch.Comment #11
jcandan commentedHiding obsolete files.
Comment #12
johnpicozzi@jcandan - Doesn't look like #10 works. I replaced the patch in #2 with #10 and the country fields first values went back to Afghanistan.
Comment #13
jcandan commented@johnpicozzi, that is very strange; this is working for me. What PHP version and Drupal version are you testing on? Did you set a default value? Make sure it is set to "None" in the field settings. As far as I can tell, if this patch is not working, it would not pass the test I provided.
Comment #14
jcandan commentedOkay, I am getting a validation error at the field settings page.
```
The country "_none" is not valid.
```
I am looking into it.
Comment #15
johnpicozziUpdate - After re-saving the address field the new patch started working. RTBC +1
Comment #16
jcandan commentedRe-rolled patch #10. This patch needs work.
This latest patch includes a set of Country field-type specific tests. The module currently does not include any tests of the Country field-type by itself, without the other Address fields. This patch includes these missing tests. It unfortunately includes a test that fails with the current fix for this issue.
The following validation error occurs after save after editing the field settings of a Country field-type field, and setting its default value to "None":
The [FIELD_NAME] "_none" is not valid.We need to identify how we can allow the field config default value to be
_none, while still ensuring the field widget is required, and_noneis not valid.Comment #17
jcandan commentedComment #18
jcandan commentedGot it! Re-rolled #16.
Went back and had a look at the patch #2. Like #2, using a blank empty value instead of
_nonedid the trick. It also helped me catch that my patch #10 missed a default value fallback when none is set and the field is required. Also fixes a hidden country field when not part of the address field-type. Also noticed #16 had a huge commented code chunk; whoops. :)I think this patch catches several test gaps, and fills them nicely while addressing this issue. Although several issues are addressed, each fix and test change was necessary for and closely linked to this issue's fix. I believe it is ready for community review.
Comment #19
jcandan commentedComment #20
jcandan commentedJust a bit more work. Just noticed that cardinality above one has an issue. If the user does "Add another item", and then wanted that item removed, the validation will not accept a blank value on that added item, which will not allow the user to submit the form, which might then remove the additional item were it to submit since it is blank.
Need to dig a little.
Comment #21
jcandan commentedThis patch significantly simplifies the fix and adds or modifies tests to deal with just the one issue: match core Select widget behavior for the Country widget; required or not, default to empty when no default specified.
For the Address widget, which includes a country select box, this patch adds an empty option. But does nothing to change its default value behavior, which is to default country to the first available valid option.
Comment #22
Juhi Rathi commentedAdded patch in which select a value option is also added in country list. Please review.
Comment #23
marko.romsak commentedI have just added the - symbols to make it more like Drupal core default behaviour. Also added the translation function. Hopefully, this will help someone.
Comment #24
dwwThanks, everyone, for working on this. Agree this would be a big UI improvement!
Patches #22 and #23 are definitely not valid code, ignore all the prior work in here, etc. Hiding those from the file table.
#21 looks pretty good. However, I'm sad about the massive copy/paste nature of
tests/src/FunctionalJavascript/AddressCountryDefaultWidgetTest.php. Yes, we want separate test coverage for the only-a-country widget, instead of only testing country as part of the address widget. Yay! However, I'd much rather see both of these extend a shared base class or have a trait where we can put everything duplicated between them in one place. That'll make it much easier to maintain these tests going forward.A few other nits/concerns on a quick skim:
We need
t('- Select -');.Sorry, these comments don't really explain WTF is happening here. ;) I probably need to apply the patch and look at the rest of this, but on quick glance, these comments need help.
Cheers,
-Derek
Comment #25
dww@jcandan Are you interested in moving this forward based on my feedback in #24? I would like to get this fixed before the next release. Thanks!
-Derek
p.s. Also fixing up issue credits based on meaningful contributions here so far.
Comment #26
jcandan commentedNicely done. Yes, I agree these are valid points. What's your timeline for release? I'll try to put some time in soon to knock this out.
Comment #27
dww@jcandan: Thanks! No specific timeline on the next release. I don't know @bojanz's plans on that, either. I'm just wanting to get obvious wins into Git before it happens. ;)
Cheers,
-Derek
Comment #28
jcandan commentedAddressed the concerns noted in #24.
Comment #29
dww@jcandan, thanks!
However, test classes don't have a
$this->t()to call (as the test results show).The bot should have already marked this issue 'Needs work' but somehow that didn't happen.
In addition to reverting all the
t()->$this->t()stuff, additional concerns/nits from looking at the patch:Doesn't look like we need the separate
$only_availablevariable, we could just do thekey(array_filter(...))directly when setting#value.This should be
protected static $modulesHaven't applied patch and inspected both test classes separately, but I wonder how much of this
setUp()could be moved into a helper method in the trait and shared...If the trait is responsible for all these data members, I'd like it to also be responsible for initializing them. Again, I suspect most (if not all) of this is duplicate between the two classes. So let's add something like an
initialize()method to the trait that's called by both setUp() functions (assuming all of setUp() can't be shared and moved wholesale into the trait).Thanks again! Excited to see this getting fixed. :)
Cheers,
-Derek
Comment #30
jcandan commentedApplied the suggestions from #29.
Comment #31
dwwSweet, thanks! Almost there. ;)
I was rather confused at first since I didn't realize you did a git patch with separate commits. Made it a bit harder to read, and is confusing the hell out of interdiff locally. So for reference, here's a clean version of #30 as a single commit.
We need this. @see #3093294: Specify the $defaultTheme property in all functional tests
Method doc blocks are supposed to start with an action verb. "Initializes Address widget tests."
This can be protected.
Seems more logical to initialize this up next to where we create the article bundle.
Attaching a patch to fix all of the above, too. Seems cruel to have you do this. ;)
HOWEVER, I just tried testing this on a local dev site where I'm actually using address (and why I care about this issue). Once I remove the default_country (which I was only setting since this bug wasn't fixed), if I load the node form, I'm still defaulting to 'Afghanistan'. :( It looks like the changes to src/Element/Country.php are specifically undoing the benefit of this fix for the country element inside an address field. :( Why so? Seems we want to duplicate (*cough*) the test coverage and actually do the fix:
Why are we doing this? I thought fixing this behavior was the whole point of this issue. ;)
We want this behavior for address fields, too. Let's include this in AddressDefaultWidgetTest.php.
Thanks, @jcandan! I promise to get this into Git ASAP once we're happy. :)
Cheers,
-Derek
Comment #32
dwwFurther nit: I think it's safer/better to avoid casting and such for cases like this. I tend to do:
Slightly more verbose, but IMHO easier to read and avoids relying on typecasting.
Comment #33
dwwI didn't mess with #32 (starting to get way out of scope for this bugfix).
But this addresses my concerns at the end of #31.
Tests pass locally.
Thoughts?
Thanks!
-Derek
Comment #34
mglamanI'm confused how or why we need to run array_filter
There is
assertSession()->asserWaitOnAjax() now
Comment #35
dww@mglaman Thanks for the review!
#34.1:
Because of the code comment you pasted:
// Filter out empty select options before count.array_filter() is maybe overkill here, but we're simply purging the empty choice before we count if there's only 1 valid option and decide to hide the country entirely and set it as a form value.
#34.2: True, but this code totally pre-dates that. ;) Maybe this isn't the best issue to change that? Do that as a quick separate issue then re-roll this?
Comment #36
dww#34.2 is now at #3096129: Replace custom waitForAjaxToFinish() with assertWaitOnAjaxRequest(). Should be a quick fix, then we can re-roll this.
Comment #37
dwwAssuming we commit #3096129: Replace custom waitForAjaxToFinish() with assertWaitOnAjaxRequest() quickly, here's a re-roll of this one to apply on top of that one. ;)
Don't queue this for testing until #3096129 lands since this won't apply.
Comment #38
dww#3096129: Replace custom waitForAjaxToFinish() with assertWaitOnAjaxRequest() is now in 8.x-1.x branch, so I queued #37 for testing.
Does anyone care about #34.1 enough to change it from an
array_filter()? If so, what do you propose as the alternative? ;)Anything else before this is RTBC?
Thanks,
-Derek
Comment #39
bojanz commentedThe patch and general approach make sense. Leaving it to dww to wrap up.
Comment #40
chris matthews commentedComment #42
dwwUpdating title to match the final patch. This doesn't actually have anything special to do with Required fields, and the actual text for the choice is just
- Select -.Committed and pushed to 8.x-1.x.
Thanks, everyone!
Cheers,
-Derek
Comment #44
bojanz commentedOpened a followup: #3116564: Selecting the "- Select -" country option does not hide address elements in some (TBD) conditions.
Comment #45
bojanz commentedUnfortunately I have had to revert this issue in https://git.drupalcode.org/project/address/commit/b95f4d6 because it introduced several regressions inside Commerce.
The first one is at checkout: #3116564: Selecting the "- Select -" country option does not hide address elements in some (TBD) conditions. The second one is on the address book UI (user/1/address-book/add/customer), where no country is selected and no fields are shown (unlike at checkout), but then selecting a country and going back to "- Please select -" shows a "Revision log message" field which I have no clue where it came from. Furthermore, a number of tests are now failing. This shows that this change is potentially too disruptive for a regular release and might need to be something we leave for 2.x.
In any case, I am reverting for the time being, to be able to tag a D9-compatible Address release. We can then come back to this issue.
Comment #46
dwwAlas. :( Sorry for the trouble. Not sure what I could have done to avoid commerce's problems. All of address.module tests were happy, and we added new tests for this, too.
Wonder if we need some additional tests in address module to make sure everything is happy inside IEF? I assume that's where most of the commerce trouble are coming from?
Comment #47
dwwWhat can we do to move this forward? How can I or anyone else test this feature in the contexts that you were having trouble with it? Are we supposed to install commerce locally? Is there a commerce quickstart distro or something? Are there docs on running a commerce test suite that shows the problems this was having? Is there something we can/should do to flesh out the test coverage here in address.module itself to catch any of these problems?
Thanks!
-Derek
Comment #48
bojanz commentedCommerce quick start: https://github.com/drupalcommerce/demo-project
#45 has the problematic urls (checkout/ and user/1/address-book/add/customer).
Tests are run like for any other Drupal module. There is a CustomerProfileTest which covers the customer profile inline form used at checkout, and a AddressBookTest functional test which covers the user pages. However, I don't think the tests are super helpful cause it's going to be hard to distinguish the expected failures (due to the select box having an extra option, for example) from the real ones.
It's very possible that the Address tests can be expanded to cover the problematic cases, but I don't know how, since I don't know what is causing the problems yet. My plan was to focus on user/1/address-book/add/customer first since it is a dumb entity form (unlike checkout which is layers of complexity).
Comment #49
bojanz commentedUnassigning myself because I no longer work on Commerce. This will have to be coordinated with mglaman or jsacksick (the current Commerce maintainers).
Comment #50
ethomas08 commentedRe-rolling patch from comment 10 for the latest release of address, 8.x-1.9.
Comment #51
alfaguru commentedI found issues with this patch when used in multi-step forms in particular. The field plugin and validators need to recognise the '_none' value as being empty, also when there is no default value the first available country is still selected.
Attached patch deals with these issues but I am sure further work is required. I am not sure why the default key has to be '_none' rather than an empty string for one, and ideally the behaviour when the field is required would be controlled by configuration.
Comment #52
alfaguru commentedComment #53
alfaguru commentedRevised version of previous patch because it causes a notice error on country widgets.
Comment #54
jacktonkin commentedRe-rolling patch from #37 against HEAD.
Comment #56
jacktonkin commentedFixing deprecations in AddressCountryDefaultWidgetTest
Comment #57
rahaf albawab commentedJust replace select with choose country
Comment #58
shivamitakari commentedReviewed and tested #57 patch and works as expected.
Comment #62
sp3boy commentedI am going with #56 which appears to work for my requirements (replacing a basic country selection with an Address field that only captures Country & Administrative Area). Not sure why anything other than "- Select -" would be a better placeholder so not applying #57 myself.
Thanks for the work!
Comment #63
bojanz commentedMoving to 2.0.x-dev, as we've closed 8.x-1.x for any risky changes, and this one definitely counts (as evidenced by #45).
Also, bumping the status back to "needs review". Both #45 and #51 indicate that the patch needs further work (or at least exploration).
Comment #64
bojanz commentedAt a glance I can definitely say that we must not modify the address element like this:
This is the big backwards compatibility break that is breaking Commerce tests.
For this patch to be committable, it needs to limit itself to the country element/field only, leaving the address UX unchanged.
Comment #65
nils.destoop commentedRe-roll of the patch on the 2.x branch as starting point
Comment #66
dwwRe: #64: I respectfully disagree. This *needs* to fix the UI of the actual address element, too, not just the country element. If you add a required address field to an entity, and do not provide a default value, the UI is quite bad. It defaults to selecting the first country in the list, which is typically not the right behavior. In all other cases, if you have a required field without a default, the form loads in a state that forces you to make a choice, and if you don't, you get a validation error. Here's a series of screenshots about it:
Current UI
Initial state of proposed UI
Browser validation error if you don't select a country
Working UI once you select a country
Sure, this isn't backwards compatible, and commerce core (and other modules that make use of address fields) might need to be modified to work with this behavior. I'm okay with putting this into a 2.1.x branch. But I'm not okay saying that only the country element can be changed, and that we're going to leave the current default-to-the-first-in-the-list behavior for address elements indefinitely.
For right now, I'm going to work on turning this into an MR, make sure it all applies cleanly to 2.0.x branch, and all the address tests are working fine. If we create a 2.1.x branch for this (and the other RTBC new features), this will merge to that branch instead of 2.0.x. I pinged folks in #commerce Slack about this, and I'm willing to coord with the Commerce Core maintainers to make sure we handle this in a way that doesn't break anyone's sites. But I'm not okay leaving this broken "forever". 😅
Thanks,
-Derek
Comment #68
dwwOkay, I took patch #37 (what I had previously committed), and turned it into an MR against 2.0.x.
Interdiff in #56 was helpful, so I used that.
I had to fix quite a bit of other stuff to get this to pass locally (on a 10.5 test site).
The pipeline is failing here, but it seems our pipelines are all sorts of messed up right now 😬 😅
https://git.drupalcode.org/project/address/-/pipelines
Probably need to pivot to cleaning that up before I get much further with this.
But the MR's plain diff is now applying happily to a local clone of a client site where I need this fixed. And it seems to work as expected, so that's all positive. 😂
Unassigning myself for now, and moving to NR, although there might be additional work to get this actually committable...
Comment #69
anybodyWe just ran into this and indeed this is confusing and for users it's a very risky issue, because on required (=important!) fields users potentially won't see that "Afghanistan" is selected. The core validation to show an error if nothing was explicitly selected is the only valid one UX-wise.
Additionally, it's confusing for site-builders and administrators to have a different behaviour here.
And if anyone wants this, they can still preselect the default value. So this hidden bug definitely should get fixed. :)
Thanks for your great work and feedback on this @dww!
PS: Regarding the discussion on Address vs. Country: Either we come to a good conclusion here or I'd vote to split the more complicated Address fix into a follow-up to get this fixed for country! Still I agree finally it should be consistent with core.
Comment #72
anybodyPlease note that the test pipeline is already broken upstream for 2.0.x-dev!
I left a comment on the MR, but would be great to be reviewed by @bojanz and @dww.
Comment #73
grevil commentedStatic patch of the current MR for the time being.
Comment #74
anybodyComment #75
anybodyLooks like there are several related issues caused by this special treatment. So there are further good reasons to fix this.
If needed perhaps special handling can be configured, if needed.