0 Draft Group Finder Share Filter Shared by Steven Hulbert, Northridge Church 3 years ago 13.7 Small Groups Beginner AboutOur church has found it helpful to send our prospective community group members links to pre-filtered sets of community groups. As the Group Finder block does not have functionality for this built in, we created a Post-HTML script that does this. With this code enabled, when you select filter settings on the group finder, the URL will be updated with parameters that track those settings. If you copy that updated URL and share it with someone else, then when they load the group finder page through that URL, it will load in the filter settings you had selected. An example can be seen below:Initial Setup1. Start by going to Home > CMS Configuration > Pages, then select the page which contains your Group Finder block.2. Click the "Block Properties" gear button on your Group Finder block:3. Navigate to the "Advanced Settings:4. Scroll down to the "Post-HTML" section and paste in the following code:<script> // Static Constants ----------------------------------------------------------------- // This mapping is used to shorten your URL parameters. On the left, you have the // built in form control names for specific filter setting on your Group Finder. On // the right, you have the name that you would like the control name shortened to in // the URL. This list can be adusted as need be for your specific use case. const sectionEncodings = new Map([ ['filter_dows', 'day'] ]); // These are automatically mirrored from the selectEncodings above. No need to edit. const sectionDecodings = new Map(); sectionEncodings.forEach((value, key) => sectionDecodings.set(value, key)); // It takes a moment for all of the page items to load properly before any selected // filters that were saved in the URL parameters should be applied. This is the time // this script should wait (in milliseconds) before attempting to modify the page. // The default is 20 milliseconds, but if you're running into issues, you can try // making it longer to allow for the page to load properly. const pageLoadTime = 20; // All of the form controls have the same base ID that prefaces the start to their // full IDs. In order to shorten all of the IDs that are stored in the URL // parameters, this base ID is automatically trimmed from the front. It is likely // that this should be consistent between all instances of the Group Finder block, // but if you find that it is different for you, then you can update it to fit. const baseId = 'ctl00_main_ctl23_ctl02_ctl08'; // This is the name of the HTML form that all of the filter setting form controls are // part of. Changes to this form are watched in order to store filter setting in the // URL parameters and load them back in on page reload. It should be called "form1" // for all instances of the Group Finder block, but if for some reason it isn't // called that for you, then you can modify this to fit what your's is called. const formName = 'form1'; // State Data and Controls ---------------------------------------------------------- const sections = new Map(); const params = new URLSearchParams(window.location.search); const form = document.forms[formName]; // Helper Functions ----------------------------------------------------------------- const setToString = (someSet) => { return Array.from(someSet).join(','); } const stringToSet = (someString) => { return new Set(someString.split(',')); } const updateParams = () => { window.history.replaceState(null, null, "?" + params); } const encodeSectionId = (sectionId) => { return sectionEncodings.get(sectionId) ?? sectionId; } const decodeSectionId = (encodedSectionId) => { return sectionDecodings.get(encodedSectionId) ?? encodedSectionId; } const addValue = (sectionId, subSectionId) => { if (sections.has(sectionId)) { sections.get(sectionId).add(subSectionId); } else { sections.set(sectionId, new Set([subSectionId])); } params.set(encodeSectionId(sectionId), setToString(sections.get(sectionId))); updateParams(); } const removeValue = (sectionId, subSectionId) => { if (sections.has(sectionId)) { const section = sections.get(sectionId); section.delete(subSectionId); if (section.size == 0) { sections.delete(sectionId); params.delete(encodeSectionId(sectionId)); } else { params.set(encodeSectionId(sectionId), setToString(section)); } updateParams(); } } const clearSection = (sectionId) => { sections.delete(sectionId); params.delete(encodeSectionId(sectionId)); updateParams(); } const handleCheckboxChange = (event, sectionId, subSectionId) => { if (event.target.checked) { addValue(sectionId, subSectionId); } else { removeValue(sectionId, subSectionId); } } const handleSelectChange = (event, uniqueId) => { const selectedOptions = Array.from(event.target.selectedOptions); clearSection(uniqueId); selectedOptions.forEach((selectedOption) => { if (selectedOption.value.length > 0) { addValue(uniqueId, selectedOption.value) } }); } const checkCheckboxFor = (sectionId, subSectionId) => { const controlId = [baseId, sectionId, subSectionId].join('_'); form.elements[controlId].checked = true; } const tryGetSelectControl = (uniqueId) => { const controlId = [baseId, uniqueId].join('_'); return form.elements[controlId]; } const selectOptionsFor = (selectControl, selectedOptions) => { const options = Array.from(selectControl.options); options.forEach((option) => { if (selectedOptions.has(option.value)) { option.selected = true; } }) } // Update URL Params on Filter Changes ---------------------------------------------- form.onchange = (event) => { const controlId = event.target.id; if (controlId.startsWith(baseId)) { // grab ID const uniqueId = controlId.substring(baseId.length + 1); const idParts = uniqueId.split('_'); const subSectionId = idParts.pop(); const sectionId = idParts.join('_'); switch (event.target.type) { case 'checkbox': handleCheckboxChange(event, sectionId, subSectionId); break; case 'select-one': case 'select-multiple': handleSelectChange(event, uniqueId); break; default: console.warn(`URL parameters does not yet support input elements of type: ${event.target.type}`); console.log(event); } } } // Load in Filter Settings from URL Params ------------------------------------------ params.forEach((selectedSubSections, encodedSectionId) => { const sectionId = decodeSectionId(encodedSectionId); subSectionIds = stringToSet(selectedSubSections); sections.set(sectionId, stringToSet(selectedSubSections)); const selectControl = tryGetSelectControl(sectionId); if (selectControl) { selectOptionsFor(selectControl, subSectionIds); } else { subSectionIds.forEach((subSectionId) => checkCheckboxFor(sectionId, subSectionId)); } }); // Click the Search Button to Autoload Results -------------------------------------- setTimeout(() => { document .getElementsByClassName("actions")[0] .getElementsByClassName("btn-primary")[0] .click(); }, pageLoadTime); </script>5. Click "Save" and you should be good to go!Advanced Configuration At the top of the script, there is a section labeled "Static Constants". These are constants you can modify to tweak the script to work with your particular group finder setup. This section describes what you can do with each of those constants. Shorten URL Parameters const sectionEncodings = ...The parameter names are pulled straight from the form control IDs of each of the filter components within the Group Finder block. These can get long and ugly. To shorten your URL and clean it up, you can set custom mappings between the built in names and your own custom names for each filter category. This mapping can easily be set up via the sectionEncodings constant as seen below: Download File