[AEM 6.4] Hide/Show drop-down / select options for more than one values
Veena Vikraman
Adobe Experience League Community Advisor (AEM). Adobe Certified AEM Architect and Senior Developer. Python , React Beginner.
Disclaimer :- As of today 8th Jan 2021, Below solution is valid only for versions upto 6.4 . From 6.5.3 the below JS is updated in /libs/cq/gui/components/authoring/dialog/dropdownshowhide/clientlibs/dropdownshowhide/js/dropdownshowhide.js .
?As per suggestions from Arun Patidar , I tried to modify the JS with a more generic version for any number of dropdown values . The same is added towards the end of the article
Recently there was a question in forum and the use case he was trying to achieve was
In tab1, there is a dropdown contains v1,v2 & v3 as its values. In tab2 there is drop down field. 1) if user select v1 & v2 in tab1, then the drop down field in tab2 should be visible. 2) if user select v3 in tab1, then the drop down field in tab2 should be disabled. 3) By default v1 will be selected , so the field in other tab should be visible.
The real catch in this usecase is that the user needs the Drop down in Tab2 to be visible for both v1 and v2. If you have a similar requirement , here is my answer
I will reiterate the same here just in case.
So there is a beautiful how to do article by Theo Pendle on how to do Conditionally show or hide a field based on a Checkbox widget.
- Follow the steps in the above article. Once you do that , you will see that , your fields are getting hidden for val2 and val3. That's perfectly alright. In the next steps we will try to modify our JS to accommodate both the dropdown values
- First let us go through the js a bit , to get an understanding on what exactly happens when we set the values mentioned in the blog
- Go to /libs/cq/gui/components/authoring/dialog/dropdownshowhide/clientlibs/dropdownshowhide/js/dropdownshowhide.js in your CRXDE and open the JS
- If we check this line, we can see that only the element with the "showhidetargetvalue" will be visible and everything else will be hidden via line 63. So to make two values work for the same logic, this is where we need to do some modifications. The beauty of data- attributes is that you can give any name and add a data-* attribute to your HTML element. So I will create another data-* attribute element and add to the field.
- Go to your component node and add another data-* attribute value as below. This value can be anything
- Next, I copied the dropdownshowhide.js JS to my component to modify it. I created a clientlib and added it as extraclientlib to my component.
- Now in the JS add an additional line to make sure the fields with the new data attribute value we added will also be showed when we select the dropdown.
Edit :- So as suggested by Arun , I tried to generalized this. Below is how I have achieved it. Below are the changes to the above steps.
- In the granite:data node of the target , we will add all the values as comma (,) separated like below
- The JS is modified as below to accommodate this change
/** * Extension to the standard dropdown/select component. It enabled hidding/unhidding of other components based on the * selection made in the dropdown/select. * * How to use: * * - add the class cq-dialog-dropdown-showhide to the dropdown/select element * - add the data attribute cq-dialog-dropdown-showhide-target to the dropdown/select element, value should be the * selector, usually a specific class name, to find all possible target elements that can be shown/hidden. * - add the target class to each target component that can be shown/hidden * - add the class hidden to each target component to make them initially hidden * - add the attribute showhidetargetvalue to each target component, the value should equal the value of the select * option that will unhide this element. */ (function(document, $) { "use strict"; // when dialog gets injected $(document).on("foundation-contentloaded", function(e) { showHideHandler($(".cq-dialog-dropdown-showhide", e.target)); }); $(document).on("selected", ".cq-dialog-dropdown-showhide", function(e) { showHideHandler($(this)); }); function showHideHandler(el) { el.each(function(i, element) { if ($(element).is("coral-select")) { // handle Coral3 base drop-down Coral.commons.ready(element, function(component) { showHide(component, element); component.on("change", function() { showHide(component, element); }); }); } else { // handle Coral2 based drop-down var component = $(element).data("select"); if (component) { showHide(component, element); } } }) } function showHide(component, element) { // get the selector to find the target elements. its stored as data-.. attribute var target = $(element).data("cqDialogDropdownShowhideTarget"); var $target = $(target); if (target) { var value; if (typeof component.value !== "undefined") { value = component.value; } else if (typeof component.getValue === "function") { value = component.getValue(); } var values = $target.attr("data-showhidetargetvalue").split(","); var targetElement = $('*[data-showhidetargetvalue]'); var $targetElement = $(targetElement) // make sure all unselected target elements are hidden. $target.not(".hide").addClass("hide"); $.each(values, function(index, targetVal) { // unhide the target element that contains the selected value as data-showhidetargetvalue attribute // $target.filter("[data-showhidetargetvalue='" + value + "']").removeClass("hide"); // deprecated if (targetVal === value) { $targetElement.removeClass("hide"); } }); } } })(document, Granite.$);
Hope this helps. I still need to test this for multifield. So I am not sure if this is gonna work for multifield yet. I will do that and give you all the modified class as soon as I do that. Meanwhile if someone get it do share it across.
Edit 2:- Thanks to Arun again. Please find below the JS which will work on all the below scenarios
1. Work with multiple values 1,2,3 or more(using multivalued property)
2. Work with multifield, we have seen show hide issues with multifield.
/** * Extension to the standard dropdown/select component. It enabled hidding/unhidding of other components based on the * selection made in the dropdown/select in multifield and multivalued. * * How to use: * * - add the class cq-dialog-dropdown-showhide-multival to the dropdown/select element * - add the data attribute cq-dialog-dropdown-showhide-target to the dropdown/select element, value should be the * selector, usually a specific class name, to find all possible target elements that can be shown/hidden. * - add the target class to each target component that can be shown/hidden * - add the class hidden to each target component to make them initially hidden * - add the attribute showhidetargetvalue to each target component, the value(or commma separated multiple values e.g. val1, val2) should equal the value of the select * option that will unhide this element. */ (function(document, $) { "use strict"; // when dialog gets injected $(document).on("foundation-contentloaded", function(e) { // if there is already an inital value make sure the according target element becomes visible showHideHandler($(".cq-dialog-dropdown-showhide-multival", e.target)); }); $(document).on("selected", ".cq-dialog-dropdown-showhide-multival", function(e) { showHideHandler($(this)); }); function showHideHandler(el) { el.each(function(i, element) { if ($(element).is("coral-select")) { // handle Coral3 base drop-down Coral.commons.ready(element, function(component) { showHide(component, element); component.on("change", function() { showHide(component, element); }); }); } else { // handle Coral2 based drop-down var component = $(element).data("select"); if (component) { showHide(component, element); } } }) } function showHide(component, element) { // get the selector to find the target elements. its stored as data-.. attribute var target = $(element).data("cqDialogDropdownShowhideTarget"); var $target = $(target); var elementIndex = $(element).closest('coral-multifield-item').index(); if (target) { var value; if (typeof component.value !== "undefined") { value = component.value; } else if (typeof component.getValue === "function") { value = component.getValue(); } $target.each(function(index) { var tarIndex = $(this).closest('coral-multifield-item').index(); if (elementIndex == tarIndex) { $(this).not(".hide").addClass("hide"); $(this).filter(function() { return $(this).data('showhidetargetvalue').replace(/ /g, '').split(',').includes(value); }).removeClass("hide"); } }); } } })(document, Granite.$);
PS:- All the naming conventions needs to be modified according to your requirement. Also, if you have a better solution please let me know.
AEM Certified | Full Stack AEM Lead Developer at Three Ireland
1 年Hi Veena Vikraman, Arun Patidar, I have a use-case and was looking for suggestions- Dropdown 1: Option 1, Option 2, Option 3 Dropdown 2 (Hidden on load) Type 1, Type 2, Type 3, Type 4 Dropdown 3 - Type 1/2(Hidden on load) Value 1, Value 2 Dropdown 3 - Type 3(Hidden on load) Value 3, Value 4 On selection of dropdown 1 option 1/2 value, dropdown 2 will be visible. On selection of dropdown 2 type 1/2, dropdown 3 - type 1 will be visible. On selection of dropdown 2 type 3 value, dropdown 3- type 3 will be visible. On selection of dropdown 2 type 4 value, dropdown 3 should be hidden. Let me know how I can achieve this. Thanks.
Sr. Product Manager, Community (Experience Manager [AEM]) at Adobe
4 年Nice one. Don't forget to share this again in the AEM community as a discussion[1]. [1] https://experienceleaguecommunities.adobe.com/t5/forums/postpage/board-id/adobe-experience-manager-discussions
AEM Architect | Adobe AEM Champion | Adobe Community Advisor | 4x Adobe ExL Community Member of the Year (2018, 2019, 2020, 2022) | Certified AEM Architect & Developer | Transforming Digital Experiences.
4 年Hi Veena Vikraman I think this is valid use case. As you asked for Suggestions. I would like to suggest to make this more generic : 1. Work with multiple values 1,2,3 or more(using multivalued property) 2. Work with multifield, we have seen show hide issues with multifield.(I can share code with you to work this in multifield)