---
# System prepended metadata

title: Untitled

---

## custom.grouphubs.infintescroll
```
<#include "api_user_creds.ftl" >
<#import "common_ug_properties.ftl" as commonUgPropertiesMacro>
<#include "events_utility_functions.ftl" >

<#assign category_id=http.request.parameters.name.get( "categoryId", "" )?html />
<#assign catHref = ""/>
<#attempt>
<#assign catInfo = rest("/categories/id/${category_id}?restapi.response_style=view")/>
<#assign catHref = catInfo.category.@view_href/>
<#recover>
</#attempt>
<@component id="angular-elipsis-lib" />

<div id="grouphub-main-wrapper" class="grouphub-main-wrapper" ng-app="userGroupsApp" ng-controller="userGroupController">
    <div class="ug-cards-title">Groups</div>
    <div id="error-container"></div>
    <div class="mobile-filter-sec">
                <div class="filter-modal-content infinite-desktop-sec">                    
                    <div class="filter-modal-main-section">
                        <div class="ug-sortby-location">
                            <label class="ug-card-label" for="existing-phases">Location</label>
                            <div class="search-location-inputbox">
                                <form ng-submit="clearLocation()">
                                    <div id='searchBoxContainer'>
                                        <input type='text' id='searchBox' aria-label="Search Location" ng-attr-placeholder="{{  userlocation.city }}"   role="combobox" ng-model='locationSearchTerm' ng-blur="clearLocation()" autocomplete="off" />
                                        <p role="alert" ng-if="isCitySelectedForGroups && selectedLocationForGroups" class="city-search-message" >
                                            Showing results within 100 mile radius
                                        </p> 
                                  </div>
                                </form>                              
                                <img src="/html/assets/location-pin.svg" alt="location pin" class="location-pin">
                            </div>
                        </div>
                    </div>
                </div>
        
        <!-- Start mobile filter section -->
        <div class="infinite-mobile-filter">
            <div class="mobile-filter-btn">
                <button id="filter-widget-btn"></button>
            </div>
            <div id="myModal" class="filter-modal">
                <div class="ug-card-filter-sectioan">
    
                    <div class="filter-modal-content">
                        <div class="filter-modal-header">
                            <h3 class="filter-modal-title">Filters</h3>
                            <span class="close"></span>
                        </div>
                        <div class="filter-modal-main-section">
                            <div class="ug-sortby-location">
                                <label class="ug-card-label" for="existing-phases">Location</label>
                                <div class="search-location-inputbox">
                                        <form ng-submit="clearLocation()">
                                        <div id='mobileSearchBoxContainer'>
                                            <input type='text' id="mobileSearchBox"  ng-attr-placeholder="{{  userlocation.city }}"  role="combobox"  aria-label="Search Location" ng-model='locationSearchTerm' ng-blur="clearLocation()" autocomplete="off" />
                                        </div>
                                         <p role="alert" ng-if="isCitySelectedForGroups && selectedLocationForGroups" class="city-search-message" >
                                            Showing results within 100 mile radius
                                        </p> 
                                    </form>
                                    <div class="filters-group-btn-sec">
                                        <button id="apply-btn" type="button" class="filters-apply-btn" >Apply</button>
                                        <button id="cancel-btn"  type="button" class="filters-cancel-btn">Cancel</button>
                                    </div>
                                    <img src="/html/assets/location-pin.svg" alt="location pin" class="location-pin">
                                </div>
                                <#--  <div id="searchResult" class="ug-search-results"></div>  -->
                            </div>
    
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <!--End mobile filter section -->
        
        <div class="ug-card-filter-section-sortby ">
            <!-- <div class="ug-sortby-category">
                    <label class="ug-card-label" for="existing-phases">Sort by</label>
                    <select class="form-control" ng-model="selectedValue" ng-change="sortBy()">
                    <option value="creationDate">Recently added</option>
                    <option value="memberCount"> Member count, high to low</option>
                    <option value="message_activity">Recent activity</option>
                </select>
                </div> -->
            <div class="m-ug-search-filter-section">
                <label class="ug-card-label" for="existing-phases">Sort by</label>
                <div class="search-dropdown">
                    <button class="select" type="button" aria-expanded="false" tabindex="0" aria-controls="sortselect">
                        <span title="{{selectedValue}}">{{selectedValue}}</span>
                        <div class="m-down-icon"></div>
                    </button>
                    <ul class="search-dropdown-menu">

                        <li  ng-repeat="option in sortOptions" id="{{option.dataKey}}"  ng-click="sortBy(option)">  <a href="javascript:void(0)" ng-attr-aria-selected="{{  option.label == selectedValue }}"   > {{option.label}} </a> </li>
                        <#--  <li id="creationDate" ng-click="sortBy('creationDate')"> <a href="javascript:void(0)">Recently added</a></li>  -->
                        <#--  <li id="memberCount" ng-click="sortBy('memberCount')"> <a href="javascript:void(0)">Member count, high to low</a></li>  -->
                        <#--  <li id="message_activity" ng-click="sortBy('message_activity')"> <a href="javascript:void(0)">Recent activity</a></li>  -->
                    </ul>
                </div>
            </div>
        </div>
    </div>
    <div class="ug-clear-both"></div>
    <div class="grouphub-result-count" ng-if="!isLoading && selectedLocationForGroups">
        <p role="alert" ng-cloak aria-label="User Groups Results {{(displayList  
                        | startFrom:(currentPage-1)*pageSize 
                        | withinGeoBoundary: selectedLocationForGroups : userlocation : isCitySelectedForGroups 
                        | customSortBy: sortFromLocation: selectedValue ).length}}">Results: {{(displayList  
                        | startFrom:(currentPage-1)*pageSize 
                        | withinGeoBoundary: selectedLocationForGroups : userlocation : isCitySelectedForGroups 
                        | customSortBy: sortFromLocation: selectedValue ).length}}</p> 
    </div>
    <div class="grouphub-list-widget" ng-cloak infinite-scroll='nextPage()' infinite-scroll-distance='2' infinite-scroll-use-document-bottom="true">
        <div class="grouphub-spinner" ng-if="isLoading">
            <div class="ug-loader"></div>
            <p>Loading ...</p>
        </div>
        <div 
            ng-if="!isLoading" 
            class="grouphubs-posts-box" 
            ng-repeat="grouphub in displayList  
                            | startFrom:(currentPage-1)*pageSize 
                            | withinGeoBoundary: selectedLocationForGroups : userlocation : isCitySelectedForGroups 
                            | customSortBy: sortFromLocation: selectedValue 
                            | limitTo:pageSize as displayResults">
            <div class="ug-card-message-img">
                <img src="{{grouphub.avatar}}"  alt="{{grouphub.title | decodeURIComponent}}"">
            </div>
            <div class="message-contents">
                <div class="grouphub-title">
                    <h3 id="{{ grouphub.id}}">
                        <a href="{{grouphub.viewHref}}" class="title-href " data-ng-bind="grouphub.title | decodeURIComponent" data-ellipsis ></a>
                    </h3>
                </div>
                <div class="grouphub-location">
                    <span data-ng-bind="grouphub.city" data-ellipsis> </span>
                </div>
                <div class="grouphub-description">
                    <span data-ng-bind="grouphub.description | decodeURIComponent" data-ellipsis></span>
                </div>
                <div class="grouphub-users">
                    <div class="grouphub-spinner" ng-if="membersLoading == true">
                        <div class="ug-loader"></div>

                    </div>
                    <div ng-if="membersLoading == false">
                        <div class="user-item" ng-repeat="user in grouphub.members | limitTo: 5 | orderBy: '-online_status'">
                            <a href="{{user.view_href}}" class="myTooltip" title="{{user.login}}"><img src="{{user.avatar.profile}}" alt="{{user.login}}" width="24" height="24">
                                <div class="{{user.online_status}}">
                                </div>
                            </a>
                        </div>
                        <div class="user-item-count" ng-if="grouphub.memberCount>5">+{{grouphub.memberCount-5}}</div>
                    </div>
                </div>
                <#-- <div class="grouphub-users">
                    <div ng-if="grouphub.members.length == 0">Loading...</div>
                    <div ng-if="grouphub.members.length != 0" class="user-item" ng-repeat="user in grouphub.members | limitTo: 5 | orderBy: '-online_status'">
                        <a href="{{user.viewHref}}"><img src="{{user.avatar}}" alt="{{user.login}}" title="{{user.login}}" width="24" height="24">
                            <div class="{{user.online_status}}">
                            </div>
                        </a>
                    </div>
            </div> -->
            <div class="ug-card-bottom-section">
                <div class="ug-learn-more-btn"><a href="{{grouphub.viewHref}}" id="Learn_more_{{grouphub.id}}" aria-labelledby="Learn_more_{{grouphub.id}} {{grouphub.id}}">Learn more</a></div>
                <#if !user.anonymous>
                    <div class="ug-join-button">
                        <div ng-switch="grouphub.memberStatus" class="ug-join-button">
                            <div ng-switch-when="joined"><button class="btn-group disabled-state" disabled>Member</button></div>
                            <div ng-switch-when="notJoined"><button class="btn-group" ng-click="joinOrRequest(grouphub)" aria-labelledby="tooltipug">Join
                            now</button></div>
                            <div ng-switch-default></div>
                        </div>
                    </div>
                </#if>
            </div>
        </div>
    </div>
    <div ng-if="displayResults.length == 0 && isLoading == false && pickedLocation " class="ug-search-empty-state">
        <@commonUgPropertiesMacro.emptyStateImage />
        <h4 role="alert">There are no groups in your area.</h4>
        <span>Get notified when new groups are added.</span>
        <div class="yg-seeall-btn">
            <a role="button" href="https://aka.ms/NewUGNotify" target="_blank" class="button-viewmore">Get notified</a>
        </div>

    </div>
    <!-- <div class="custom-no-group-hubs" ng-if="showLocationEmptyContent && pickedLocation">
                    <p>No group hubs with this selected range</p>
                </div> -->
    <div class="ug-notified-box-wrapper" ng-if="pickedLocation && displayResults.length != 0"  >
     <div class="ug-notified-box">       
        <div class="ug-notified-box-content"><p>Get notified when there’s a group in your area. New groups are added regularly.</p></div>
        <div class="ug-notified-button"><a role="button" href="https://aka.ms/NewUGNotify" target="_blank">Get notified</a></div>
       </div>
    </div>
</div>

</div>
<script type="text/javascript">


    var locationObj 
    function loadMapScenario() {

        var prevValue =''
        var latitude
        var longitude
        document.getElementById("filter-widget-btn")
        .addEventListener("click", function () {
            prevValue = document.getElementById("mobileSearchBox").value || ""
            console.log("trigger value for p",prevValue)
        })
        Microsoft.Maps.loadModule('Microsoft.Maps.AutoSuggest', {
            callback: onLoad,
            errorCallback: onError
        });
        Microsoft.Maps.loadModule('Microsoft.Maps.SpatialDataService',   {
            callback: function () {
                var scope = angular
                            .element(document.getElementById("grouphub-main-wrapper"))
                            .scope();
                scope.onInit()
                scope.$apply()
            }
        });
        function onLoad() {


            var options = {
                maxResults: 5
            };
            var manager = new Microsoft.Maps.AutosuggestManager(options);
            function initAutoSuggest () {
                var searchBoxId = window.innerWidth < 680 ? "#mobileSearchBox" : "#searchBox"
                var searchBoxContainerId = window.innerWidth < 680 ? "#mobileSearchBoxContainer" : "#searchBoxContainer"
                manager.attachAutosuggest(
                    searchBoxId, 
                    searchBoxContainerId,
                    selectedSuggestion
                );
            }
            initAutoSuggest()
            var isMobile = (/iphone|ipod|android|ie|blackberry|fennec/).test(navigator.userAgent.toLowerCase());

            if (!isMobile){
                window.addEventListener('resize',function () {
                    manager.detachAutosuggest()
                    initAutoSuggest()
                })

            }


              if (window.innerWidth < 680){

                    function hidePopup ()  {
                        modal.style.display = "none";
                        filterBtn.className = "filters-apply-btn"
                    }
                    var modal = document.getElementById("myModal");
                    var applyBtn = document.getElementById("apply-btn");  
                    var cancelBtn = document.getElementById("cancel-btn");
                    applyBtn.addEventListener('click', function () { 
                        var scope = angular
                            .element(document.getElementById("grouphub-main-wrapper"))
                            .scope();
                        scope.getdest(locationObj);
                        scope.$apply();
                        hidePopup()
                    })
                    cancelBtn.addEventListener('click', function () { 
                        
                        var scope = angular
                            .element(document.getElementById("grouphub-main-wrapper"))
                            .scope();
                        
                        scope.clearLocation()
                        scope.$apply()
                        console.log("prev value is ", prevValue)
                        if (prevValue){
                            document.getElementById("mobileSearchBox").value  = prevValue
                        }
                        hidePopup()
                    })
              }
        }
        

        function onError(message) {  
          //loadMapScenario()
            var containerId  = "error-container"
            var errorElement = `<div  class="location-failed-error-message" ><p>Your location failed to load. Please refresh the page.</p><span id ="location-error-snap"  class="error-close-btn"></span></div>`
            console.log("error in loading big api " , message)
            document.getElementById(containerId).innerHTML = errorElement;
            document.getElementById("location-error-snap").addEventListener("click", function () { 
                document.getElementById(containerId).innerHTML = "";
            })
        }

        //onError()

        function selectedSuggestion(suggestionResult) {
            lat = suggestionResult.location.latitude;
            lon = suggestionResult.location.longitude;
            city = suggestionResult.formattedSuggestion;
            
            var scope = angular
                .element(document.getElementById("grouphub-main-wrapper"))
                .scope();
            if (window.innerWidth < 680){
                locationObj = suggestionResult
                latitude= suggestionResult.location.latitude
                longitude = suggestionResult.location.longitude

            } else {  
                scope.getdest(suggestionResult);
                scope.$apply();
            }

        }
    }

    function modifyGroupsWithLocationCoordinates (groups) {
        return groups.map(function (eachGroup) {
            eachGroup.locationCoordinates = { 
                latitude : parseFloat(eachGroup.latitude),
                longitude : parseFloat(eachGroup.longitude)
            }
            return eachGroup
        })
    }


    <#--  function ellipseForElements(ele) {
        $('.grouphub-card-description-ellipse').tilesdes();
        $('.grouphub-card-title-ellipse').tilesdes();
        $('.grouphub-card-location-ellipse').tilesdes();
    }  -->
    var userGroupApp = angular.module('userGroupsApp', ["infinite-scroll","dibari.angular-ellipsis"]);
    <#--  userGroupApp.directive('repeatLast', function() {
        return function(scope, element, attrs) {
            if (scope.$last) {
                setTimeout(ellipseForElements, 1000, element);
            } else {
                ellipseForElements(element);
            }
        };
    });  -->

    function setToolTip () {
        setTimeout(function () {
            $(".myTooltip").zTip();
        },1000)
    }
    userGroupApp.controller('userGroupController', ['$scope', '$http', '$filter', function($scope, $http, $filter) {

        // start:  location handling  values

        $scope.pickedLocation = false
        $scope.locationSearchTerm = ""
            // end:  location handling  values

        $scope.sourceList = []
        $scope.displayList = []
        $scope.users = [];

        // $scope.displayList = [];
        $scope.pageSize = 12;
        $scope.currentPage = 1;
        $scope.groupsLength = 0;
        $scope.selectedValue = 'Nearby location';
        $scope.isLoading = true;
        $scope.membersLoading = true;
        $scope.recentActivityResponse = []

        $scope.selectedLocationForGroups = null
        $scope.isCitySelectedForGroups = false

        $scope.sortFromLocation = null



        $scope.sortOptions = [ 
             {
                label: "Nearby location",
                dataKey: "distance"
            },
            {
                label: "Recently added",
                dataKey: "creationDate"
            },
            {
                label: "Member count, high to low",
                dataKey: "memberCount"
            },
            {
                label: "Recent activity",
                dataKey: "message_activity"
            },
           
        ]
        // get user location 
        $scope.userlocation = null

        $scope.onInit = function () {
            getUserLocation( function (location)  { 
                  var applyFn = function () {
                    console.log("user is location",location )
                    $scope.userlocation = location
                    $scope.sortBy($scope.sortOptions[0])
                    $scope.sortFromLocation = location

                };
                if ($scope.$$phase) {
                    applyFn();
                } else {
                    $scope.$apply(applyFn);
                }
            })
        };
        $http.get('${webuisupport.urls.endpoints.name.get("get-grouphubs").build()}?categoryId=${category_id}' + '&orderBy=creation_date')
            .then(function(response) {


                var modifiedGroups =  modifyGroupsWithLocationCoordinates(response.data.grouphubs);

                $scope.isLoading = false;
                $scope.sourceList = modifiedGroups;
                $scope.displayList = modifiedGroups;
                console.log("total list is ", $scope.displayList)


                $scope.displayList.map(function(obj) {
                    if (!obj.hasOwnProperty('distance')) {
                        obj.distance = 0;
                    }
                })

                $scope.groupsLength = $scope.sourceList.length;
                $scope.updateGroupUsers();
            }, function(error) {
                console.log("error", error);
            });
        $scope.nextPage = function() {
            if ($scope.groupsLength > $scope.pageSize) {
                $scope.pageSize += $scope.pageSize
                setToolTip()
            }
        }
        $scope.clearLocation = function() {
            if ($scope.locationSearchTerm.length == 0) {
                $scope.displayList = $scope.sourceList;
                $scope.pickedLocation = false
                $scope.selectedLocationForGroups = null
                $scope.sortFromLocation = $scope.userlocation
                setToolTip()
            }
        };
        $scope.sortBy = function(selectedOption) {


            console.log("sort called", selectedOption)
            $scope.selectedValue = selectedOption.label
            var sortField = selectedOption.dataKey
            $(".select").attr('aria-expanded', 'false');
            $(".search-dropdown").find(".search-dropdown-menu").slideUp(300);
            if (sortField ==="distance") {
                var userlocation = $scope.sortFromLocation !== null ? $scope.sortFromLocation : $scope.userlocation
                var arrayWithDistance = $scope.displayList.map(function (item) {
                    var listItemCoordinates = {
                        latitude: item.locationCoordinates&& item.locationCoordinates.latitude ,
                        longitude: item.locationCoordinates&& item.locationCoordinates.longitude ,
                    }
                    item.distance = distanceCal(userlocation.latitude, userlocation.longitude, listItemCoordinates.latitude, listItemCoordinates.longitude, "K")
                    return item
                })
                var sortedEvents = arrayWithDistance.sort(function (groupA, groupB) {
                    var a = groupA.distance
                    var b = groupB.distance
                    if( !isFinite(a) && !isFinite(b) ) {
                        return 0;
                    }
                    if( !isFinite(a) ) {
                        return 1;
                    }
                    if( !isFinite(b) ) {
                        return -1;
                    }
                    return a-b;
                })
                console.log("after sorting is ", arrayWithDistance);
                $scope.displayList =  sortedEvents
            } else if (sortField === "creationDate") {
                $scope.displayList =  $scope.displayList.sort(function(groupA, groupB) {
                    return moment(groupB.creationDateISOString) - moment(groupA.creationDateISOString)
                })
            } else if (sortField === "memberCount") {
                $scope.displayList =  $scope.sourceList.sort(function(groupA, groupB) {
                    return groupA.memberCount > groupB.memberCount ? -1 : 1
                });
            } else if (sortField === "message_activity") {
                function handleRecentAcitivityResponse(responseArray) {
                    return responseArray.map(function(group) {
                        const groupObj = $scope.sourceList.find(function(g) {
                            return g.id === group.id
                        })
                        return groupObj
                    })
                }
                if ($scope.recentActivityResponse.length === 0) {
                    $scope.isLoading = true;
                    $http.get('${webuisupport.urls.endpoints.name.get("get-grouphubs").build()}?categoryId=${category_id}' + '&orderBy=message_activity.core_property_change_time')
                        .then(function(response) {
                            $scope.recentActivityResponse = handleRecentAcitivityResponse(response.data.grouphubs)

                            console.log("after sort response is ", $scope.recentActivityResponse)
                            $scope.isLoading = false;
                            if ($scope.pickedLocation) {
                                console.log('case with location', $scope.displayList)
                                $scope.displayList = $scope.recentActivityResponse.filter(function(group) {
                                    var existingInDisplayListIndex = $scope.displayList.findIndex(function(i) {
                                        return i.id === group.id
                                    })
                                    return existingInDisplayListIndex !== -1
                                });
                                setToolTip()

                            } else {
                                $scope.displayList = $scope.recentActivityResponse
                                $scope.sourceList = $scope.recentActivityResponse
                            }
                            $scope.groupsLength = $scope.displayList.length;

                        }, function(error) {
                            console.log("error", error);
                        });

                } else {
                    if ($scope.pickedLocation) {
                        var responseCopy = Object.assign([], $scope.recentActivityResponse)
                        $scope.displayList = responseCopy.filter(function(group) {
                            var existingInDisplayListIndex = $scope.displayList.findIndex(function(i) {
                                return i.id === group.id
                            })
                            return existingInDisplayListIndex !== -1
                        });

                    } else {
                        $scope.displayList = $scope.recentActivityResponse
                    }
                    $scope.groupsLength = $scope.sourceList.length;

                }
            } else if (sortField === "creationDate") {
                var displayListCopy = Object.assign([], $scope.displayList);
                $scope.displayList = displayListCopy.sort(function(a, b) {
                    return new Date(b[sortField]) - new Date(a[sortField]);
                });
            }
            setToolTip()

        };

        $scope.joinOrRequest = function(node) {
            $http.get('${webuisupport.urls.endpoints.name.get("join-or-send-request-grouphub").query("mode","join").build()}&boardId=' + node.id)
                .then(function(response) {
                        if (response.data.respStatus == "success") {
                            node.memberStatus = "joined";
                            var learnMoreLink = "Learn_more_"+node.id
                            node.memberCount += 1;
                            toastMessage("You’re now a member of the group! ","","You can access all your groups in Your groups tab.","${catHref}?target=your_groups","Go to Your groups", null, learnMoreLink);
                            setToolTip()
                        } else {
                            node.memberStatus = "";
                        }
                    },
                    function(response) {
                        console.log("error", response);
                        node.memberStatus = "";
                    });
        }

        $scope.updateGroupUsers = function() {
            var batchMaxSize = 25
            var batchedGroupHubs = chunkArray($scope.sourceList, batchMaxSize)
            
            var allCopy = Object.assign([], $scope.sourceList)
            
            batchedGroupHubs.map(function (currentBatchGroups,currentBatchIndex) {
                recursiveFetcher(currentBatchGroups, function (response) {
                        console.log("calling final setter ",currentBatchIndex,currentBatchIndex * batchMaxSize , (currentBatchIndex *   batchMaxSize)+ batchMaxSize)
                        var currentBatchScopedListOriginal = allCopy.slice(currentBatchIndex * batchMaxSize,(currentBatchIndex *   batchMaxSize)+ batchMaxSize)
                            
                        var currentBatchScopedList =  currentBatchScopedListOriginal.map(function(groupHub, index) {
                            groupHub.members = response[index * 2].items;
                            groupHub.memberCount = response[index * 2 + 1].count;
                            return groupHub
                        });

                        console.log("afterresponse is ", currentBatchScopedList)

                        angular.forEach($scope.sourceList, function (value, itemIndex) {

                            var foundIndex = currentBatchScopedList.findIndex(function (g) {
                                return value.id === g.id
                            })
                            var foundOne = currentBatchScopedList[foundIndex]
                            
                            if (itemIndex ===foundIndex) {
                                value.members = foundOne.members;
                                value.memberCount = foundOne.memberCount;
                            }
                        })
                        angular.forEach($scope.displayList, function (value, itemIndex) {

                            var foundIndex = currentBatchScopedList.findIndex(function (g) {
                                return value.id === g.id
                            })
                            var foundOne = currentBatchScopedList[foundIndex]
                            
                            if (itemIndex ===foundIndex) {
                                value.members = foundOne.members;
                                value.memberCount = foundOne.memberCount;
                            }
                        })

                        $scope.membersLoading = false;
                        setToolTip()
                })
            })

            function recursiveFetcher(batch, onEnd) {

                var userObj = "[";
                angular.forEach(batch, function(value, key) {
                    if (userObj != "[") {
                        userObj = userObj + ",";
                    }
                    userObj =
                        userObj +
                        '{"users": {"fields": ["id","login","view_href","online_status","avatar"],"constraints": [{"node.id": "grouphub:' +
                        value.id +
                        '"}]}},{"users": {"fields": ["count(*)"],"constraints": [{"node.id": "grouphub:' +
                        value.id +
                        '"}]}}';
                });
                userObj = userObj + "]";
                $http({
                    url: '/api/2.0/search',
                    dataType: 'json',
                    method: 'POST',
                    <#if user.anonymous>
                        headers:{
                            'li-api-session-key': '${sessionKey}',
                        },
                    </#if>
                    data: userObj,
                    contentType: "application/json",
                }).then(
                    function(response) {
                        onEnd(response.data.data)
                    },
                    function(error) {
                        console.log("error", error);
                    }
                );
            }
           

        }

        $scope.getdest = function(loc) {
            if ($scope.locationSearchTerm.length === 0 ){
                $scope.clearLocation()
                return 
            }
            var selectionType  = evalSelectionType(loc)
                var pickedLocation = { 
                    latitude: loc.location.latitude,
                    longitude: loc.location.longitude,
                    state: loc.address.adminDistrict,
                    country: loc.address.countryRegion
                }
                $scope.isLoading = true;
                var applyFn = function () {
                    $scope.isLoading = false;
                    if (selectionType === "city"){
                        $scope.selectedLocationForGroups = {
                            location: pickedLocation,   
                            bounds: null, 
                        }
                        $scope.sortFromLocation = $scope.userlocation
                    }
                    else {
                        $scope.selectedLocationForGroups = {
                            location: pickedLocation,   
                            bounds: true, 
                        }
                        $scope.sortFromLocation = $scope.userlocation
                    }
                    $scope.pickedLocation = true
                    $scope.isCitySelectedForGroups = selectionType === "city"
                    setToolTip()
                };
                if ($scope.$$phase) {
                    applyFn();
                } else {
                    $scope.$apply(applyFn);
                }
                console.log("selected type id ", selectionType)
              
        };
    }])

    userGroupApp.filter("customSortBy", function () {
        return function (oldArray, sortFromLocation, field) {
            console.log("sort with field ", field)
            if (field === "Nearby location"){
                var oldArrayWithDistance = oldArray.map(function (item) {
                    var listItemCoordinates = {
                        latitude: item.locationCoordinates && item.locationCoordinates.latitude,
                        longitude: item.locationCoordinates && item.locationCoordinates.longitude,
                    }
                    item.distance = distanceCal(sortFromLocation.latitude, sortFromLocation.longitude, listItemCoordinates.latitude, listItemCoordinates.longitude, "K")
                    return item
                })
                return oldArrayWithDistance.sort(function (itemA, itemB) {
                    var a = itemA.distance
                    var b = itemB.distance
                    if( !isFinite(a) && !isFinite(b) ) {
                        return 0;
                    }
                    if( !isFinite(a) ) {
                        return 1;
                    }
                    if( !isFinite(b) ) {
                        return -1;
                    }
                    return a-b;
                })
            }
            else {
                return oldArray
            }
        }
    })
    userGroupApp.filter('decodeURIComponent', function() {
        return window.decodeURIComponent;
    })
    userGroupApp.filter('startFrom', function() {
        return function(input, start) {
            if (input) {
                start = +start;
                return input.slice(start);
            }
            return [];
        };
    })
    userGroupApp.filter('truncate', function() {
        return function(value, wordwise, max, tail) {
            if (!value) return '';
            max = parseInt(max, 10);
            if (!max) return value;
            if (value.length <= max) return value;

            value = value.substr(0, max);
            if (wordwise) {
                var lastspace = value.lastIndexOf(' ');
                if (lastspace != -1) {
                    value = value.substr(0, lastspace);
                }
            }
            return value + (tail || ' …');
        };
    });
    userGroupApp.filter("withinGeoBoundary", function () {
        return angularFilters.withinGeoBoundary
    })

    var MODULE_NAME = 'infinite-scroll'
    angular.module(MODULE_NAME, [])
        .value('THROTTLE_MILLISECONDS', null)
        .directive('infiniteScroll', [
            '$rootScope', '$window', '$interval', 'THROTTLE_MILLISECONDS',
            function($rootScope, $window, $interval, THROTTLE_MILLISECONDS) {
                return {
                    scope: {
                        infiniteScroll: '&',
                        infiniteScrollContainer: '=',
                        infiniteScrollDistance: '=',
                        infiniteScrollDisabled: '=',
                        infiniteScrollUseDocumentBottom: '=',
                        infiniteScrollListenForEvent: '@',
                    },

                    link: function(scope, elem, attrs) {
                        var windowElement = angular.element($window);

                        var scrollDistance = null;
                        var scrollEnabled = null;
                        var checkWhenEnabled = null;
                        var container = null;
                        var immediateCheck = true;
                        var useDocumentBottom = false;
                        var unregisterEventListener = null;
                        var checkInterval = false;

                        function height(element) {
                            var el = element[0] || element;

                            if (isNaN(el.offsetHeight)) {
                                return el.document.documentElement.clientHeight;
                            }
                            return el.offsetHeight;
                        }

                        function pageYOffset(element) {
                            var el = element[0] || element;

                            if (isNaN(window.pageYOffset)) {
                                return el.document.documentElement.scrollTop;
                            }
                            return el.ownerDocument.defaultView.pageYOffset;
                        }

                        function offsetTop(element) {
                            if (!(!element[0].getBoundingClientRect || element.css('none'))) {
                                return element[0].getBoundingClientRect().top + pageYOffset(element);
                            }
                            return undefined;
                        }

                        // infinite-scroll specifies a function to call when the window,
                        // or some other container specified by infinite-scroll-container,
                        // is scrolled within a certain range from the bottom of the
                        // document. It is recommended to use infinite-scroll-disabled
                        // with a boolean that is set to true when the function is
                        // called in order to throttle the function call.
                        function defaultHandler() {
                            var containerBottom;
                            var elementBottom;
                            if (container === windowElement) {
                                containerBottom = height(container) + pageYOffset(container[0].document.documentElement);
                                elementBottom = offsetTop(elem) + height(elem);
                            } else {
                                containerBottom = height(container);
                                var containerTopOffset = 0;
                                if (offsetTop(container) !== undefined) {
                                    containerTopOffset = offsetTop(container);
                                }
                                elementBottom = (offsetTop(elem) - containerTopOffset) + height(elem);
                            }

                            if (useDocumentBottom) {
                                elementBottom = height((elem[0].ownerDocument || elem[0].document).documentElement);
                            }

                            var remaining = elementBottom - containerBottom;
                            var shouldScroll = remaining <= (height(container) * scrollDistance) + 1;

                            if (shouldScroll) {
                                checkWhenEnabled = true;

                                if (scrollEnabled) {
                                    if (scope.$$phase || $rootScope.$$phase) {
                                        scope.infiniteScroll();
                                    } else {
                                        scope.$apply(scope.infiniteScroll);
                                    }
                                }
                            } else {
                                if (checkInterval) {
                                    $interval.cancel(checkInterval);
                                }
                                checkWhenEnabled = false;
                            }
                        }

                        // The optional THROTTLE_MILLISECONDS configuration value specifies
                        // a minimum time that should elapse between each call to the
                        // handler. N.b. the first call the handler will be run
                        // immediately, and the final call will always result in the
                        // handler being called after the `wait` period elapses.
                        // A slimmed down version of underscore's implementation.
                        function throttle(func, wait) {
                            var timeout = null;
                            var previous = 0;

                            function later() {
                                previous = new Date().getTime();
                                $interval.cancel(timeout);
                                timeout = null;
                                return func.call();
                            }

                            function throttled() {
                                var now = new Date().getTime();
                                var remaining = wait - (now - previous);
                                if (remaining <= 0) {
                                    $interval.cancel(timeout);
                                    timeout = null;
                                    previous = now;
                                    func.call();
                                } else if (!timeout) {
                                    timeout = $interval(later, remaining, 1);
                                }
                            }

                            return throttled;
                        }

                        var handler = (THROTTLE_MILLISECONDS != null) ?
                            throttle(defaultHandler, THROTTLE_MILLISECONDS) :
                            defaultHandler;

                        function handleDestroy() {
                            container.unbind('scroll', handler);
                            if (unregisterEventListener != null) {
                                unregisterEventListener();
                                unregisterEventListener = null;
                            }
                            if (checkInterval) {
                                $interval.cancel(checkInterval);
                            }
                        }

                        scope.$on('$destroy', handleDestroy);

                        // infinite-scroll-distance specifies how close to the bottom of the page
                        // the window is allowed to be before we trigger a new scroll. The value
                        // provided is multiplied by the container height; for example, to load
                        // more when the bottom of the page is less than 3 container heights away,
                        // specify a value of 3. Defaults to 0.
                        function handleInfiniteScrollDistance(v) {
                            scrollDistance = parseFloat(v) || 0;
                        }

                        scope.$watch('infiniteScrollDistance', handleInfiniteScrollDistance);
                        // If I don't explicitly call the handler here, tests fail. Don't know why yet.
                        handleInfiniteScrollDistance(scope.infiniteScrollDistance);

                        // infinite-scroll-disabled specifies a boolean that will keep the
                        // infnite scroll function from being called; this is useful for
                        // debouncing or throttling the function call. If an infinite
                        // scroll is triggered but this value evaluates to true, then
                        // once it switches back to false the infinite scroll function
                        // will be triggered again.
                        function handleInfiniteScrollDisabled(v) {
                            scrollEnabled = !v;
                            if (scrollEnabled && checkWhenEnabled) {
                                checkWhenEnabled = false;
                                handler();
                            }
                        }

                        scope.$watch('infiniteScrollDisabled', handleInfiniteScrollDisabled);
                        // If I don't explicitly call the handler here, tests fail. Don't know why yet.
                        handleInfiniteScrollDisabled(scope.infiniteScrollDisabled);

                        // use the bottom of the document instead of the element's bottom.
                        // This useful when the element does not have a height due to its
                        // children being absolute positioned.
                        function handleInfiniteScrollUseDocumentBottom(v) {
                            useDocumentBottom = v;
                        }

                        scope.$watch('infiniteScrollUseDocumentBottom', handleInfiniteScrollUseDocumentBottom);
                        handleInfiniteScrollUseDocumentBottom(scope.infiniteScrollUseDocumentBottom);

                        // infinite-scroll-container sets the container which we want to be
                        // infinte scrolled, instead of the whole window. Must be an
                        // Angular or jQuery element, or, if jQuery is loaded,
                        // a jQuery selector as a string.
                        function changeContainer(newContainer) {
                            if (container != null) {
                                container.unbind('scroll', handler);
                            }

                            container = newContainer;
                            if (newContainer != null) {
                                container.bind('scroll', handler);
                            }
                        }

                        changeContainer(windowElement);

                        if (scope.infiniteScrollListenForEvent) {
                            unregisterEventListener = $rootScope.$on(scope.infiniteScrollListenForEvent, handler);
                        }

                        function handleInfiniteScrollContainer(newContainer) {
                            // TODO: For some reason newContainer is sometimes null instead
                            // of the empty array, which Angular is supposed to pass when the
                            // element is not defined
                            // (https://github.com/sroze/ngInfiniteScroll/pull/7#commitcomment-5748431).
                            // So I leave both checks.
                            if ((!(newContainer != null)) || newContainer.length === 0) {
                                return;
                            }

                            var newerContainer;

                            if (newContainer.nodeType && newContainer.nodeType === 1) {
                                newerContainer = angular.element(newContainer);
                            } else if (typeof newContainer.append === 'function') {
                                newerContainer = angular.element(newContainer[newContainer.length - 1]);
                            } else if (typeof newContainer === 'string') {
                                newerContainer = angular.element(document.querySelector(newContainer));
                            } else {
                                newerContainer = newContainer;
                            }

                            if (newerContainer == null) {
                                throw new Error('invalid infinite-scroll-container attribute.');
                            }
                            changeContainer(newerContainer);
                        }

                        scope.$watch('infiniteScrollContainer', handleInfiniteScrollContainer);
                        handleInfiniteScrollContainer(scope.infiniteScrollContainer || []);

                        // infinite-scroll-parent establishes this element's parent as the
                        // container infinitely scrolled instead of the whole window.
                        if (attrs.infiniteScrollParent != null) {
                            changeContainer(angular.element(elem.parent()));
                        }

                        // infinte-scoll-immediate-check sets whether or not run the
                        // expression passed on infinite-scroll for the first time when the
                        // directive first loads, before any actual scroll.
                        if (attrs.infiniteScrollImmediateCheck != null) {
                            immediateCheck = scope.$eval(attrs.infiniteScrollImmediateCheck);
                        }

                        function intervalCheck() {
                            if (immediateCheck) {
                                handler();
                            }
                            return $interval.cancel(checkInterval);
                        }

                        checkInterval = $interval(intervalCheck);
                        return checkInterval;
                    },
                }
            },

        ]);
</script>
<script type="text/javascript">
    (function(root, $) {
        'use strict';
        $.fn.tilesdes = function() {
            return this.each(function() {
                var $this = $(this),
                    isOverflow = $this.css('overflow') === 'hidden';
                if (isOverflow) {
                    var text = $this.text(),
                        lh = parseInt($this.css('line-height')),
                        line = $this.attr('data-tilesdes'),
                        maxHeight = lh * line;

                    for (var i = text.length; i > 0; i--) {
                        if ($this.height() <= maxHeight) {
                            break;
                        } else {
                            $this.text(text.substr(0, i) + '...');
                        }
                    }
                }
            });
        }
    }(window, jQuery));
    $(document).ready(function() {
        $('.grouphub-card-description-ellipse').tilesdes();
        $('.grouphub-card-title-ellipse').tilesdes();
        $('.grouphub-card-location-ellipse').tilesdes();
    });

    $(window).resize(function() {
        $('.grouphub-card-description-ellipse').tilesdes();
        $('.grouphub-card-title-ellipse').tilesdes();
        $('.grouphub-card-location-ellipse').tilesdes();
    });
     
        
    /*start Dropdown Menu*/
     // event handler to hide menu when focused on outside elements
    $(".ug-card-filter-section-sortby").on('focusout', function(event) {
        if (this.contains(event.relatedTarget)) {
            // don't react to this
            return;
        }
        $(".search-dropdown-menu").slideUp(300);
        $(".select").attr('aria-expanded', 'false');
        // do something
    });
    
    $(".search-dropdown-menu").keydown(function(e){


        console.log("event ", e.key)
        switch (e.key) {
            case "ArrowUp" :
                e.preventDefault();
                $(this).closest('.dropdown-menu').find('a:first').focus();
                break;
            case "ArrowDown" :
                e.preventDefault();
                $(this).closest('.dropdown-menu').find('a:first').focus();
                break;
        }
    });
    $(".select").on("keyup click", function (event) {
        if ((event.keyCode == '13' && event.type == "keydown" && event.key == "Escape") || event.type ==
            "click") {
            event.preventDefault();
            if ($(event.target).hasClass('active') == true || $(event.target).parent().hasClass(
                'active') == true) {
                $(this).attr('aria-expanded', 'false');
            } else {
                $(this).attr('aria-expanded', 'true');
            }
            $(this).toggleClass("active");
            $(".search-dropdown").find(".search-dropdown-menu").slideToggle(300);
        }
    });
    $(".search-dropdown").on("keyup", function (event) {
        if (event.keyCode == '27') {
            event.preventDefault();
            if ($(event.target).hasClass('active') == true || $(event.target).parent().hasClass(
                'active') == true) {
                $(this).attr('aria-expanded', 'false');

            } else {
                $(this).attr('aria-expanded', 'true');

            }
            $('.select').focus();
            $(".search-dropdown").find(".search-dropdown-menu").slideUp(300);


        }
    });
    $(".c .search-dropdown-menu li").click(function () {
        $(this).parents(".search-dropdown").find("span").text($(this).text());
        $(this)
            .parents(".search-dropdown")
            .find("input")
            .attr("value", $(this).attr("id"));
    });
    $(".search-dropdown-menu li").click(function () {
        var input =
            "<strong>" +
            $(this).parents(".search-dropdown").find("input").val() +
            "</strong>",
            msg = '<span class="msg">Hidden input value: ';
        $(".msg").html(msg + input + "</span>");
    });
    $(".search-dropdown-menu").on("keyup", function (event) {
        if (event.keyCode == '13') {
            event.preventDefault();
            if ($(event.target).hasClass('active') == true || $(event.target).parent().hasClass(
                'active') == true) {
                $(this).attr('aria-expanded', 'false');

            } else {
                $(this).attr('aria-expanded', 'true');

            }
            $('.select').focus();
            $(this).removeClass("active");
            $(".search-dropdown").find(".search-dropdown-menu").slideUp(300);
        }
    });
    window.addEventListener('click', function(e){   
        var dropdowns = document.getElementsByClassName('search-dropdown')
        var check =   dropdowns[0].contains(e.target) 
        console.log("chefk is ", check)
        if (check){
        // Clicked in box
        } else{
            $(".select").attr('aria-expanded', 'false');
            $(".select").removeClass("active");
            if (window.innerWidth > 640) {
            $(".search-dropdown").find(".search-dropdown-menu").slideUp(300);
            }
        // Clicked outside the box
        }
    });

    /*End Dropdown Menu*/

</script>
<script>
    $(window).on("load resize", function() {
        if ($(this).width() < 680) {
            var modal = document.getElementById("myModal");
            // Get the button that opens the modal
            var btn = document.getElementById("filter-widget-btn");
            // Get the <span> element that closes the modal
            var span = document.getElementsByClassName("close")[0];
            // When the user clicks the button, open the modal 
            btn.onclick = function() {
                modal.style.display = "block";
                btn.classList.add("disabled-filter-icon")
            }
            // When the user clicks on <span> (x), close the modal
            span.onclick = function() {
                modal.style.display = "none";
            }
        }
    })
</script>
```