Problem/Motivation
Applying the states API to a vertical tab removes the tab content, but not the link in the vertical tab menu:

Steps to reproduce:
$form['toggle_visible'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Toggle visibility'),
'#default_value' => FALSE,
);
$form['vertical_tabs1'] = array(
'#type' => 'vertical_tabs',
'#default_tab' => 'edit-details1',
);
$form['details1'] = array(
'#type' => 'details',
'#title' => $this->t('details1'),
'#open' => TRUE,
'#group' => 'vertical_tabs1',
'#states' => array(
'visible' => array(
'input[name=toggle_visible]' => array('checked' => FALSE),
),
),
);
Proposed resolution
Make states apply to the vertical tab and update the vertical tab menu accordingly.
Remaining tasks
- Write a patch
- Review
- Commit
User interface changes
States are applied to the vertical tab and update the vertical tab menu accordingly.
API changes
To be determined.
Data model changes
None.
Original report by Berdir:
See #767212-12: #states can't hide/show fieldsets.
The attached patch fixes it, it's probably a bit hackish, but that was the best I could come up with my limited JS skills :)
What it does is add a derived id (based on the fieldset id) to each vertical tab li element. Then it overrides the state:visibile handler for those fieldsets and instead hides/shows the corresponding button. It also switches back to the nearest fieldset if it is currently active when hidden again.
I guess it might be possible to pass the vertical_tab element somehow directly to that bind callback, which would make that id stuff unecessary.
| Comment | File | Size | Author |
|---|---|---|---|
| #91 | 1148950-91.patch | 1.36 KB | andreastkdf |
| #89 | 1148950-nr-bot.txt | 9 KB | needs-review-queue-bot |
| #88 | 1148950-88.patch | 1.36 KB | _utsavsharma |
| #87 | 1148950-86-reroll-9.5.patch | 3.61 KB | seanb |
| #85 | 1148950-86-reroll-9.4.patch | 3.24 KB | seanb |
Comments
Comment #1
berdirTagged.
Comment #2
sunI fear the "select another vertical tab" logic is not necessarily complete - I had similarly simple code in filter.admin.js in the beginning, but thorough manual testing revealed lots of bugs with that. Of course, filter.admin.js doesn't use #states, but the active vertical tab logic should be comparable.
Comment #3
berdirI'll check that out.
I've only tested it with having a fieldset in the middle and with having one in the beginning, and it worked fine for me.
Comment #4
BenK commentedSubscribing
Comment #5
anonSubscribing
Comment #6
anon@Sun, What do you think of this patch?
Its from D7 dev.
Comment #7
anonChanged the Drupal verison, if this isnt ok, then please change it back.
Comment #8
Johnny vd Laar commentedThe patch breaks the functionality to assign menu's to nodes.
Comment #9
Johnny vd Laar commentedThis patch solves the problem by looking into the e.target
Comment #10
anonThis patch is the same as in #9 but it also hides the wrapping div when no fieldsets are visible.
Comment #11
berdirThis needs to be fixed in 8.x first, and then backported.
Comment #12
fenda commentedLooking to sponsor someone to get this fixed in D8 and back ported to D7. Message me off interested!
Comment #13
nod_need D8 reroll and use
e.preventDefault();instead ofreturn false;Comment #14
cweagansFixing tags per http://drupal.org/node/1517250
Comment #15
wim leersBump, would be nice to have this fixed in D8 :)
Comment #16
wim leersMarked #1777970: Vertical tabs don't support #state visibility as a duplicate of this one.
Comment #17
dealancer commentedI've tried patch #10. It works, however when the verical tab is shown it also gets focus, which should not happen. This is because tabShow() is called which does focus: "this.focus();".
Comment #18
dealancer commentedHere is re rolled patch which fixes problem described in #17.
Comment #19
dealancer commentedComment #22
josephdpurcell commentedThis patch appears to work correctly. I can confirm that by adding a vertical tab with config like:
The tab is hidden.
I have a few nit picks:
Perhaps more readable would be:
Similar to line ~49.
This comment is either obscure, or misplaced.
Comment #23
josephdpurcell commentedThis is a small-ish chunk of work that someone could sprint on today.
Comment #24
lucastockmann commentedWorking on this in dublin.
Comment #25
lucastockmann commentedRe-rolled this patch. Also followed comments #13 and #22.
Tested with this snippet:
Comment #26
lucastockmann commentedComment #28
steffenrI'll have a look on your patch luca.
Comment #29
steffenrLooks fine for me - i did some testing with a custom field to hide/show the "Advanced" field section on the node form.
Thx luca.
Comment #30
manuel garcia commentedIndentation is off here
Comment #31
manuel garcia commentedFixing #30.
As a side note, core includes a
.editorconfigfile, which you can use to help prevent indentation issues in the future =) - just install http://editorconfig.org/#download for your IDE of choice and you'll be all set.Comment #32
droplet commentedWe already used jQuery inside the script, let use jQuery.on and adding the namespace to the event.
$tabPaneSet
Comment #33
droplet commentedComment #34
mbrc commentedComment #35
mbrc commentedNotes:
tabHide()to hide the tab if it's currently active/visible. If we're hiding an inactive tab, we just need to hide the tab title. This way we prevent the unwanted refocusing of tabs.stopPropagation()instead ofpreventDefault()to prevent bubbling.Comment #36
mbrc commentedRemoving "fieldsets" from the title, since in D8 we're not using them anymore to create vertical tabs.
Comment #37
nod_+ var $tabPaneSet = $(this);
we alreday have $this defined earlier, do we need this new variable?
Also I'm really not looking forward to having #states code outside states.js. Can we at least separate this callback in a differnet file, verticaltabs.states.js for exemple? I'd feel better.
Comment #38
manuel garcia commentedComment #39
manuel garcia commentedSimple one, just addressing
+ var $tabPaneSet = $(this);Still needs work based on #37.
Comment #40
manuel garcia commentedWhile working on this, I've found that this is already working fine on 8.3.x at least.
I have built a test module for this purpose, which you can find attached. It sets up a form with a few different use cases, different states and it seems fine even on nested vertical tabs.
I haven not been able to find any steps to reproduce this problem so I am postponing this issue for now, feel free to check out the attached module to double check.
Comment #41
manuel garcia commentedRe #40 just enable the module and go to
/vertical_tabs_states_test/form/defaultComment #42
navneet0693 commentedI am not able to reproduce it ! The module upload by @Manuel is working without problem, even examples VerticalTabsDemo, http://cgit.drupalcode.org/examples/tree/fapi_example/src/Form works fine.
Comment #44
idebr commentedI can confirm the states API works for
#type => vertical_tabs, but not#type => details, see the screen capture in the updated issue summary.Comment #45
manuel garcia commentedThanks @idebr for the report, can you share here the code to see/troubleshoot the bug please?
Comment #46
idebr commentedHey Manuel,
I updated the test module you supplied in #40 and moved the states to the details. The code I changed is available in the issue summary
Comment #47
manuel garcia commentedRerolling #39 due to #2818825: Rename all JS files to *.es6.js and compile them .
I now see what you mean @idebr, and you're right, that doesn't work at the moment, so thanks a LOT for following up on this!
So yes we do need to fix this.
One thing to note is that for the optional state, you actually have to use it on the input fields themselves, doesn't work if you use it on details, not sure if this is a bug we should fix as well, or if its ok to be like this. The rest of the states changes do work on details with the patch applied though.
I attach the updated module to test the states on details, and also showing that last bit I mention about optional states (enable and go to
/vertical_tabs_states_test/form/default)Comment #48
manuel garcia commentedSome more findings, toggling enabled on details works without the patch on #47.
So so far the ones not working without the patch that I know of are:
With the patch applied, still not working:
Comment #50
manuel garcia commentedReroll due to #2880007: Auto-fix ESLint errors and warnings
Comment #51
robpowell#50 worked for me.Disregard, wrong page.Comment #52
markhalliwellI can verify that this fixes the issue. I thought I was configuring the #states array incorrectly or missing some "special case" since it was vertical tabs. Glad to know this is actually a bug. I have to say though, this is a pretty big bug and the priority should probably be escalated and backport patches be made.
Comment #53
xjmThanks for working on this!
The current fix introduces a few errors in our JS coding style rules. Before:
With patch:
Reference: #2912962: Step 1 JS codestyle: [meta] Fix JS coding standards in core
We probably also need an automated test that will ensure the bug stays fixed. Thanks!
Comment #54
GrandmaGlassesRopeMan- Fixes coding standards issues.
Comment #55
droplet commentedCan we have a better name and with namespacing?
in what case, "e.target != this" ?
can we add some comments to show what this condition trying to do?
any better way to skip $.show? can we verify it in another non-DOM manipulation way? Thanks.
** Missing tests
Comment #56
zahord commentedHi all,
I was checking the issue and send an update with a different approach just updating the vertical-tab title to set the same status and allow the default behavior for the status works and trying to affect less vertical-tabs js.
I hope this works!
Regards.
Comment #57
zahord commentedComment #59
seanbRerolled #54 for 8.5 and 8.6 (patch applies to both).
Comment #61
seanb*edit* Commented on wrong issue, sorry...
Comment #62
seanbI missed a small change. Think this should fix it.
Comment #63
askibinski commentedIt seems the cody style was changed to camelCase in #2915784: 1/3 JS codestyle: camelcase.
vertical_tab -> verticalTab
Comment #64
manuel garcia commentedThanks for the heads up @askibinski addressing #63 here.
Comment #66
idebr commentedReroll against 8.7.x after #2981652: [Aug. 9 2018] Format core JavaScript using recently add Prettier was committed.
Still needs an automated JavaScript test.
Comment #68
manuel garcia commentedInitial tests for #states is being worked on here #2702233: [backport] Add JavaScript tests for Form API #states: required, visible, invisible, expanded, checked, unchecked
Comment #69
manuel garcia commentedSetting to needs work to address #55 and for adding test coverage.
Comment #70
geaseTo me, patch in #66 doesn't fix the issue. It hides a tab when it is inactive, but for an active (open) tab, it hides the tab, but the content doesn't change. Imho, in case of hiding an active tab, it should be hidden with its content and default tab should be made active (content displayed and the tab itself should be selected).
Comment #74
seanbReroll for 9.1.x
Comment #77
cilefen commentedA reroll of #74 for 9.3.x.
Comment #78
cilefen commentedFix the code style.
Comment #79
cilefen commented#78 applies but wrongly hides vertical tabs for us in the situation described in this issue so I think it needs work.
Comment #80
cilefen commentedI think that
thisbecame bound to the wrong value with the changes due to deprecating jquery.once.Claro theme has a copy of this JavaScript and will need to be changed too.
Comment #81
askibinski commented@cilefen
Your patch at #80 causes an undefined variable "verticalTab".
You are right though that Claro has a mostly identical copy of these js, except for some classnames I think. So I created a patch based on #78 for Claro, since most people are probably going to use Claro or Gin these days. Not sure if this issue needs splitting for that, because eventually I believe the Claro override js will be removed when #3081489: Remove duplicate code from veritcal-tabs.js in Claro is implemented. So, an alternative would be to work on that issue, create a core patch for that and then use the patch for misc/js.
I also stripped the "If there are no visible tab panes, hide the whole vertical-tabs area" part since it adds a bit of fragile code and the current approach left me with a lot of leftover styling/classes in Claro (when using vertical tabs with field_group) which maybe could better be handled in a separate ticket.
Also also, I created a similar patch for when horizontal tabs are used with the field_group module: #3264569: Support applying #states to a horizontal tab
Comment #82
adrianliegmann commentedComment #84
cilefen commentedSo I think for this to be commit-able we need patches for the plain and Claro files.
Comment #85
seanbAll duplicate claro code has been removed in #3081489: Remove duplicate code from veritcal-tabs.js in Claro. Rerolled the patch for 9.4.
Comment #87
seanbAnother reroll for 9.5.
Comment #88
_utsavsharma commentedReroll for 10.1.x.
Please review.
Comment #89
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #91
andreastkdf commentedReroll for 10.2.x
Comment #92
chili.hh commentedThe patch from #91 works as far as #states are usable for vertical tabs. However, with Drupal v10.4.0 I currently encounter the problem, that the initial state of impacted tabs is not set correctly. In other words, in my form I have a checkbox that should determine if a tab menu entry for a tab should be visible as long as the checkbox is actually checked. If the initial state of the checkbox is unchecked, the corresponding tab menu entry still get displayed nevertheless until I uncheck and re-check the controlling checkbox. The initial display of the tab contents works though (so, the to be conditionally displayed tab contents itself is NOT visible - it's just the menu entry in the tab menu).
It seems to me as if only the visibility state of the tab menu entry is set wrong for the initial state and it's not a fault of the controlling checkbox/form element. Why do I think that? Because in the tab that is to be conditionally displayed (for which the menu entry should NOT be visible, but is indeed accessible and therefore one can navigate to the tab contents) there are form elements contained that should receive a "required" flag when the same checkbox that is controlling the tab visibility is checked - and this works. In the initial state (so, when the tab itself is wrongly displayed) the dependant form elements within that tab are NOT required and only get required once the checkbox is actually ticked.
Unfortunately I was not able to spot the code fragment that's responsible for the state initialization and therefore can't provide an updated patch. :-(
// edit:
I just realized that the patch from #91 ist NOT code fragment causing the problem! On line 92 of the vertical-tabs script there is the command "tabList.append(verticalTab.item);" that unconditionally adds a menu entry to the tab menu. This should only get done conditionally...